From 726899b14339a006e88631d5014adb209ef4ab1c Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 20 Nov 2025 21:15:21 +1100 Subject: [PATCH 1/5] Add SEEED_ARCH_MIX (mimxrt) v1.26.1 Signed-off-by: Andrew Leech --- .../LICENSE.md | 22 + .../README.md | 37 + .../__builtins__.pyi | 28 + .../_onewire.pyi | 15 + .../binascii.pyi | 61 + .../cmath.pyi | 84 + .../cryptolib.pyi | 165 + .../deflate.pyi | 89 + .../dht.pyi | 26 + .../ds18x20.pyi | 18 + .../errno.pyi | 97 + .../framebuf.pyi | 247 ++ .../gc.pyi | 112 + .../hashlib.pyi | 116 + .../heapq.pyi | 46 + .../lwip.pyi | 51 + .../machine.pyi | 3251 +++++++++++++++++ .../math.pyi | 269 ++ .../micropython.pyi | 346 ++ .../mimxrt.pyi | 14 + .../mip/__init__.pyi | 38 + .../network.pyi | 551 +++ .../ntptime.pyi | 15 + .../onewire.pyi | 28 + .../platform.pyi | 51 + .../pyproject.toml | 108 + .../random.pyi | 115 + .../requests/__init__.pyi | 42 + .../select.pyi | 118 + .../socket.pyi | 426 +++ .../time.pyi | 306 ++ .../tls.pyi | 26 + .../uarray.pyi | 2 + .../uasyncio.pyi | 2 + .../ubinascii.pyi | 2 + .../ubluetooth.pyi | 2 + .../ucollections.pyi | 15 + .../ucryptolib.pyi | 2 + .../uctypes.pyi | 164 + .../uerrno.pyi | 2 + .../uhashlib.pyi | 2 + .../uheapq.pyi | 2 + .../uio.pyi | 2 + .../ujson.pyi | 2 + .../umachine.pyi | 2 + .../uos.pyi | 2 + .../uplatform.pyi | 2 + .../urandom.pyi | 2 + .../ure.pyi | 2 + .../urequests.pyi | 25 + .../uselect.pyi | 2 + .../usocket.pyi | 2 + .../ussl.pyi | 2 + .../ustruct.pyi | 2 + .../usys.pyi | 2 + .../utime.pyi | 2 + .../uwebsocket.pyi | 2 + .../uzlib.pyi | 2 + .../vfs.pyi | 240 ++ .../websocket.pyi | 17 + .../_onewire.pyi | 15 + .../binascii.pyi | 61 + .../cmath.pyi | 84 + .../cryptolib.pyi | 165 + .../deflate.pyi | 89 + .../dht.pyi | 26 + .../doc_stubs.json | 476 +++ .../ds18x20.pyi | 18 + .../errno.pyi | 97 + .../firmware_stubs.json | 80 + .../framebuf.pyi | 247 ++ .../gc.pyi | 112 + .../hashlib.pyi | 116 + .../heapq.pyi | 46 + .../lwip.pyi | 51 + .../machine.pyi | 3251 +++++++++++++++++ .../math.pyi | 269 ++ .../micropython.pyi | 346 ++ .../mimxrt.pyi | 14 + .../mip/__init__.pyi | 38 + .../network.pyi | 551 +++ .../ntptime.pyi | 15 + .../onewire.pyi | 28 + .../platform.pyi | 51 + .../random.pyi | 115 + .../requests/__init__.pyi | 42 + .../select.pyi | 118 + .../socket.pyi | 426 +++ .../time.pyi | 306 ++ .../tls.pyi | 26 + .../uarray.pyi | 2 + .../uasyncio.pyi | 2 + .../ubinascii.pyi | 2 + .../ubluetooth.pyi | 2 + .../ucollections.pyi | 137 + .../ucryptolib.pyi | 2 + .../uctypes.pyi | 164 + .../uerrno.pyi | 2 + .../uhashlib.pyi | 2 + .../uheapq.pyi | 2 + .../uio.pyi | 2 + .../ujson.pyi | 2 + .../umachine.pyi | 2 + .../uos.pyi | 2 + .../uplatform.pyi | 2 + .../urandom.pyi | 2 + .../ure.pyi | 2 + .../urequests.pyi | 25 + .../uselect.pyi | 2 + .../usocket.pyi | 2 + .../ussl.pyi | 2 + .../ustruct.pyi | 2 + .../usys.pyi | 2 + .../utime.pyi | 2 + .../uwebsocket.pyi | 2 + .../uzlib.pyi | 2 + .../vfs.pyi | 240 ++ .../websocket.pyi | 17 + .../_asyncio.pyi | 18 + .../_onewire.pyi | 15 + .../array.pyi | 13 + .../asyncio/__init__.pyi | 278 ++ .../asyncio/core.pyi | 73 + .../asyncio/event.pyi | 25 + .../asyncio/funcs.pyi | 22 + .../asyncio/lock.pyi | 16 + .../asyncio/stream.pyi | 96 + .../binascii.pyi | 14 + .../builtins.pyi | 305 ++ .../cmath.pyi | 21 + .../collections.pyi | 33 + .../cryptolib.pyi | 13 + .../deflate.pyi | 22 + .../dht.pyi | 26 + .../ds18x20.pyi | 18 + .../errno.pyi | 33 + .../framebuf.pyi | 35 + .../gc.pyi | 16 + .../hashlib.pyi | 23 + .../heapq.pyi | 12 + .../io.pyi | 37 + .../json.pyi | 13 + .../lwip.pyi | 51 + .../machine.pyi | 416 +++ .../math.pyi | 55 + .../micropython.pyi | 28 + .../mimxrt.pyi | 14 + .../mip.pyi | 22 + .../mip/__init__.pyi | 38 + .../modules.json | 80 + .../network.pyi | 47 + .../ntptime.pyi | 15 + .../onewire.pyi | 28 + .../os.pyi | 61 + .../platform.pyi | 12 + .../random.pyi | 16 + .../requests.pyi | 24 + .../requests/__init__.pyi | 42 + .../select.pyi | 17 + .../socket.pyi | 51 + .../ssl.pyi | 28 + .../struct.pyi | 14 + .../sys.pyi | 27 + .../time.pyi | 22 + .../tls.pyi | 26 + .../uarray.pyi | 14 + .../uasyncio/__init__.pyi | 278 ++ .../uasyncio/core.pyi | 73 + .../uasyncio/event.pyi | 25 + .../uasyncio/funcs.pyi | 22 + .../uasyncio/lock.pyi | 16 + .../uasyncio/stream.pyi | 96 + .../ubinascii.pyi | 15 + .../ucollections.pyi | 34 + .../ucryptolib.pyi | 14 + .../uctypes.pyi | 50 + .../uerrno.pyi | 33 + .../uhashlib.pyi | 24 + .../uheapq.pyi | 13 + .../uio.pyi | 38 + .../ujson.pyi | 14 + .../umachine.pyi | 416 +++ .../uos.pyi | 62 + .../uplatform.pyi | 13 + .../urandom.pyi | 17 + .../ure.pyi | 14 + .../urequests.pyi | 25 + .../uselect.pyi | 17 + .../usocket.pyi | 51 + .../ustruct.pyi | 15 + .../usys.pyi | 28 + .../utime.pyi | 23 + .../uwebsocket.pyi | 18 + .../vfs.pyi | 43 + .../websocket.pyi | 17 + 195 files changed, 19162 insertions(+) create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/LICENSE.md create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/README.md create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/__builtins__.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/_onewire.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/binascii.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/cmath.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/cryptolib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/deflate.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/dht.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ds18x20.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/errno.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/framebuf.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/gc.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/hashlib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/heapq.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/lwip.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/machine.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/math.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/micropython.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mimxrt.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mip/__init__.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/network.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ntptime.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/onewire.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/platform.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/pyproject.toml create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/random.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/requests/__init__.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/select.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/socket.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/time.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/tls.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uarray.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uasyncio.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ubinascii.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ubluetooth.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ucollections.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ucryptolib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uctypes.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uerrno.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uhashlib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uheapq.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uio.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ujson.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/umachine.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uos.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uplatform.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/urandom.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ure.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/urequests.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uselect.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/usocket.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ussl.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ustruct.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/usys.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/utime.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uwebsocket.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uzlib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/vfs.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/websocket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/_onewire.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/binascii.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/cmath.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/cryptolib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/deflate.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/dht.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/doc_stubs.json create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/errno.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/firmware_stubs.json create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/framebuf.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/gc.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/hashlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/heapq.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/lwip.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/machine.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/math.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/micropython.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/mimxrt.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/network.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/platform.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/random.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/select.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/socket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/time.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/tls.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uarray.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uasyncio.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ubinascii.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ubluetooth.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ucollections.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ucryptolib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uctypes.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uerrno.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uhashlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uheapq.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uio.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ujson.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/umachine.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uos.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uplatform.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/urandom.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ure.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uselect.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/usocket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ussl.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ustruct.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/usys.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/utime.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uwebsocket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uzlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/vfs.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/websocket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_asyncio.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_onewire.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/array.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/core.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/event.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/funcs.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/lock.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/stream.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/binascii.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/builtins.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cmath.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/collections.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cryptolib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/deflate.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/dht.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/errno.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/framebuf.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/gc.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/hashlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/heapq.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/io.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/json.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/lwip.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/machine.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/math.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/micropython.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mimxrt.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/modules.json create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/network.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/os.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/platform.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/random.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/select.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/socket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/struct.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/sys.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/time.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/tls.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uarray.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/core.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/event.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/funcs.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/lock.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/stream.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ubinascii.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucollections.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucryptolib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uctypes.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uerrno.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uhashlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uheapq.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uio.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ujson.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/umachine.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uos.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uplatform.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urandom.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ure.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uselect.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usocket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ustruct.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usys.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/utime.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uwebsocket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/vfs.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/websocket.pyi diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/LICENSE.md b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/LICENSE.md new file mode 100644 index 000000000..15d4b4693 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/LICENSE.md @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2022 Jos Verlinde + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/README.md b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/README.md new file mode 100644 index 000000000..6d13a3529 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/README.md @@ -0,0 +1,37 @@ +# micropython-mimxrt-seeed_arch_mix-stubs + + +This is a stub-only package for MicroPython. +It is intended to be installed in a projects virtual environment to allow static type checkers and intellisense features to be used while writing Micropython code. + +The version of this package is alligned the the version of the MicroPython firmware. + - Major, Minor and Patch levels are alligned to the same version as the firmware. + - The post release level is used to publish new releases of the stubs. + +For `Micropython 1.17` the stubs are published as `1.17.post1` ... `1.17.post2` +for `Micropython 1.18` the stubs are published as `1.18.post1` ... `1.18.post2` + +To install the latest stubs: +`pip install -I micropython--stubs` where port is the port of the MicroPython firmware. + +To install the stubs for an older version, such as MicroPython 1.17: +`pip install micropython-stm32-stubs==1.17.*` which will install the last post release of the stubs for MicroPython 1.17. + + +As the creation of the stubs, and merging of the different types is still going though improvements, the stub packages are marked as Beta. +To upgrade stubs to the latest stubs for a specific version use `pip install micropython-stm32-stubs==1.17.* --upgrade` + +If you have suggestions or find any issues with the stubs, please report them in the [MicroPython-stubs Discussions](https://github.com/Josverl/micropython-stubs/discussions) + +For an overview of Micropython Stubs please see: https://micropython-stubs.readthedocs.io/en/main/ + * List of all stubs : https://micropython-stubs.readthedocs.io/en/main/firmware_grp.html + + + +Included stubs: +* Merged stubs from `stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged` +* Core stubs from `stubs/micropython-core` + + +origin | Family | Port | Board | Version +-------|--------|------|-------|-------- diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/__builtins__.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/__builtins__.pyi new file mode 100644 index 000000000..5d9ece1df --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/__builtins__.pyi @@ -0,0 +1,28 @@ +"""Allows for type checking of Micropython specific builtins by pyright and pylance. +""" + +from typing import Tuple, TypeVar + +Const_T = TypeVar("Const_T", int, float, str, bytes, Tuple) # constant + +def const(expr: Const_T) -> Const_T: + """ + Used to declare that the expression is a constant so that the compiler can + optimise it. The use of this function should be as follows:: + + from micropython import const + + CONST_X = const(123) + CONST_Y = const(2 * CONST_X + 1) + + Constants declared this way are still accessible as global variables from + outside the module they are declared in. On the other hand, if a constant + begins with an underscore then it is hidden, it is not available as a global + variable, and does not take up any memory during execution. + + This `const` function is recognised directly by the MicroPython parser and is + provided as part of the :mod:`micropython` module mainly so that scripts can be + written which run under both CPython and MicroPython, by following the above + pattern. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/_onewire.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/_onewire.pyi new file mode 100644 index 000000000..2e9c634f3 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/_onewire.pyi @@ -0,0 +1,15 @@ +""" +Module: '_onewire' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def reset(*args, **kwargs) -> Incomplete: ... +def writebyte(*args, **kwargs) -> Incomplete: ... +def writebit(*args, **kwargs) -> Incomplete: ... +def crc8(*args, **kwargs) -> Incomplete: ... +def readbyte(*args, **kwargs) -> Incomplete: ... +def readbit(*args, **kwargs) -> Incomplete: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/binascii.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/binascii.pyi new file mode 100644 index 000000000..3bea9ae53 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/binascii.pyi @@ -0,0 +1,61 @@ +""" +Binary/ASCII conversions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/binascii.html + +CPython module: :mod:`python:binascii` https://docs.python.org/3/library/binascii.html . + +This module implements conversions between binary data and various +encodings of it in ASCII form (in both directions). + +--- +Module: 'binascii' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any, Optional +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def crc32(data, value: Optional[Any] = None) -> Incomplete: + """ + Compute CRC-32, the 32-bit checksum of *data*, starting with an initial CRC + of *value*. The default initial CRC is zero. The algorithm is consistent + with the ZIP file checksum. + """ + ... + +def hexlify(data: bytes, sep: str | bytes = ..., /) -> bytes: + """ + Convert the bytes in the *data* object to a hexadecimal representation. + Returns a bytes object. + + If the additional argument *sep* is supplied it is used as a separator + between hexadecimal values. + """ + ... + +def unhexlify(data: str | bytes, /) -> bytes: + """ + Convert hexadecimal data to binary representation. Returns bytes string. + (i.e. inverse of hexlify) + """ + ... + +def b2a_base64(data: bytes, /) -> bytes: + """ + Encode binary data in base64 format, as in `RFC 3548 + `_. Returns the encoded data + followed by a newline character if newline is true, as a bytes object. + """ + ... + +def a2b_base64(data: str | bytes, /) -> bytes: + """ + Decode base64-encoded data, ignoring invalid characters in the input. + Conforms to `RFC 2045 s.6.8 `_. + Returns a bytes object. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/cmath.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/cmath.pyi new file mode 100644 index 000000000..a20e1eea1 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/cmath.pyi @@ -0,0 +1,84 @@ +""" +Mathematical functions for complex numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/cmath.html + +CPython module: :mod:`python:cmath` https://docs.python.org/3/library/cmath.html . + +The ``cmath`` module provides some basic mathematical functions for +working with complex numbers. + +Availability: not available on WiPy and ESP8266. Floating point support +required for this module. + +--- +Module: 'cmath' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsComplex, SupportsFloat, SupportsIndex, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_C: TypeAlias = SupportsFloat | SupportsComplex | SupportsIndex | complex + +e: float = 2.718281828459045 +"""base of the natural logarithm""" +pi: float = 3.141592653589793 +"""the ratio of a circle's circumference to its diameter""" + +def polar(z: _C, /) -> Tuple: + """ + Returns, as a tuple, the polar form of ``z``. + """ + ... + +def sqrt(z: _C, /) -> complex: + """ + Return the square-root of ``z``. + """ + ... + +def rect(r: float, phi: float, /) -> float: + """ + Returns the complex number with modulus ``r`` and phase ``phi``. + """ + ... + +def sin(z: _C, /) -> float: + """ + Return the sine of ``z``. + """ + ... + +def exp(z: _C, /) -> float: + """ + Return the exponential of ``z``. + """ + ... + +def cos(z: _C, /) -> float: + """ + Return the cosine of ``z``. + """ + ... + +def phase(z: _C, /) -> float: + """ + Returns the phase of the number ``z``, in the range (-pi, +pi]. + """ + ... + +def log(z: _C, /) -> float: + """ + Return the natural logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... + +def log10(z: _C, /) -> float: + """ + Return the base-10 logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/cryptolib.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/cryptolib.pyi new file mode 100644 index 000000000..e6dd78a9d --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/cryptolib.pyi @@ -0,0 +1,165 @@ +""" +Cryptographic ciphers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/cryptolib.html + +--- +Module: 'cryptolib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +class aes: + """ + .. class:: aes + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, IV: AnyReadableBuf, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, IV: AnyReadableBuf, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/deflate.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/deflate.pyi new file mode 100644 index 000000000..9366f529f --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/deflate.pyi @@ -0,0 +1,89 @@ +""" +Deflate compression & decompression. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/deflate.html + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ +(commonly used in the zlib library and gzip archiver). + +**Availability:** + +* Added in MicroPython v1.21. + +* Decompression: Enabled via the ``MICROPY_PY_DEFLATE`` build option, on by default + on ports with the "extra features" level or higher (which is most boards). + +* Compression: Enabled via the ``MICROPY_PY_DEFLATE_COMPRESS`` build option, on + by default on ports with the "full features" level or higher (generally this means + you need to build your own firmware to enable this). + +--- +Module: 'deflate' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +GZIP: Final[int] = 3 +"""Supported values for the *format* parameter.""" +RAW: Final[int] = 1 +"""Supported values for the *format* parameter.""" +ZLIB: Final[int] = 2 +"""Supported values for the *format* parameter.""" +AUTO: Final[int] = 0 +"""Supported values for the *format* parameter.""" + +class DeflateIO: + """ + This class can be used to wrap a *stream* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + The *stream* must be a blocking stream. Non-blocking streams are currently + not supported. + + The *format* can be set to any of the constants defined below, and defaults + to ``AUTO`` which for decompressing will auto-detect gzip or zlib streams, + and for compressing it will generate a raw stream. + + The *wbits* parameter sets the base-2 logarithm of the DEFLATE dictionary + window size. So for example, setting *wbits* to ``10`` sets the window size + to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to + window sizes of 32 to 32k bytes). + + If *wbits* is set to ``0`` (the default), then for compression a window size + of 256 bytes will be used (as if *wbits* was set to 8). For decompression, it + depends on the format: + + * ``RAW`` will use 256 bytes (corresponding to *wbits* set to 8). + * ``ZLIB`` (or ``AUTO`` with zlib detected) will use the value from the zlib + header. + * ``GZIP`` (or ``AUTO`` with gzip detected) will use 32 kilobytes + (corresponding to *wbits* set to 15). + + See the :ref:`window size ` notes below for more information + about the window size, zlib, and gzip streams. + + If *close* is set to ``True`` then the underlying stream will be closed + automatically when the :class:`deflate.DeflateIO` stream is closed. This is + useful if you want to return a :class:`deflate.DeflateIO` stream that wraps + another stream and not have the caller need to know about managing the + underlying stream. + + If compression is enabled, a given :class:`deflate.DeflateIO` instance + supports both reading and writing. For example, a bidirectional stream like + a socket can be wrapped, which allows for compression/decompression in both + directions. + """ + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, stream, format=AUTO, wbits=0, close=False, /) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/dht.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/dht.pyi new file mode 100644 index 000000000..3a5da285f --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/dht.pyi @@ -0,0 +1,26 @@ +""" +Module: 'dht' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def dht_readinto(*args, **kwargs) -> Incomplete: ... + +class DHTBase: + def measure(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT22: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT11: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ds18x20.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ds18x20.pyi new file mode 100644 index 000000000..cf3ac9fc2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ds18x20.pyi @@ -0,0 +1,18 @@ +""" +Module: 'ds18x20' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def const(*args, **kwargs) -> Incomplete: ... + +class DS18X20: + def read_scratch(self, *args, **kwargs) -> Incomplete: ... + def read_temp(self, *args, **kwargs) -> Incomplete: ... + def write_scratch(self, *args, **kwargs) -> Incomplete: ... + def convert_temp(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/errno.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/errno.pyi new file mode 100644 index 000000000..0a736a827 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/errno.pyi @@ -0,0 +1,97 @@ +""" +System error codes. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/errno.html + +CPython module: :mod:`python:errno` https://docs.python.org/3/library/errno.html . + +This module provides access to symbolic error codes for `OSError` exception. +A particular inventory of codes depends on :term:`MicroPython port`. + +--- +Module: 'errno' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +ENOBUFS: Final[int] = 105 +"""No buffer space available""" +ENODEV: Final[int] = 19 +"""No such device""" +ENOENT: Final[int] = 2 +"""No such file or directory""" +EISDIR: Final[int] = 21 +"""Is a directory""" +EIO: Final[int] = 5 +"""I/O error""" +EINVAL: Final[int] = 22 +"""Invalid argument""" +EPERM: Final[int] = 1 +"""Operation not permitted""" +ETIMEDOUT: Final[int] = 116 +"""Connection timed out""" +ENOMEM: Final[int] = 12 +"""Out of memory""" +EOPNOTSUPP: Final[int] = 95 +"""Operation not supported""" +ENOTCONN: Final[int] = 128 +"""Transport endpoint is not connected""" +errorcode: dict = {} +"""\ +Dictionary mapping numeric error codes to strings with symbolic error +code (see above):: + +>>> print(errno.errorcode[errno.EEXIST]) +EEXIST +""" +EAGAIN: Final[int] = 11 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EALREADY: Final[int] = 120 +"""Operation already in progress""" +EBADF: Final[int] = 9 +"""Bad file descriptor""" +EADDRINUSE: Final[int] = 112 +"""Address already in use""" +EACCES: Final[int] = 13 +"""Permission denied""" +EINPROGRESS: Final[int] = 119 +"""Operation now in progress""" +EEXIST: Final[int] = 17 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EHOSTUNREACH: Final[int] = 118 +"""Host is unreachable""" +ECONNABORTED: Final[int] = 113 +"""Connection aborted""" +ECONNRESET: Final[int] = 104 +"""Connection reset by peer""" +ECONNREFUSED: Final[int] = 111 +"""Connection refused""" +ENOTSUP: Final[int] = ... +"""Operation not supported""" diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/framebuf.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/framebuf.pyi new file mode 100644 index 000000000..2f57ae0e7 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/framebuf.pyi @@ -0,0 +1,247 @@ +""" +Frame buffer manipulation. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/framebuf.html + +This module provides a general frame buffer which can be used to create +bitmap images, which can then be sent to a display. + +--- +Module: 'framebuf' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Optional, Union, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +MONO_HMSB: Final[int] = 4 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +MONO_HLSB: Final[int] = 3 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +RGB565: Final[int] = 1 +"""Red Green Blue (16-bit, 5+6+5) color format""" +MONO_VLSB: Final[int] = 0 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are vertically mapped with +bit 0 being nearest the top of the screen. Consequently each byte occupies +8 vertical pixels. Subsequent bytes appear at successive horizontal +locations until the rightmost edge is reached. Further bytes are rendered +at locations starting at the leftmost edge, 8 pixels lower. +""" +MVLSB: Final[int] = 0 +GS2_HMSB: Final[int] = 5 +"""Grayscale (2-bit) color format""" +GS8: Final[int] = 6 +"""Grayscale (8-bit) color format""" +GS4_HMSB: Final[int] = 2 +"""Grayscale (4-bit) color format""" + +def FrameBuffer1(*args, **kwargs) -> Incomplete: ... + +class FrameBuffer: + """ + The FrameBuffer class provides a pixel buffer which can be drawn upon with + pixels, lines, rectangles, text and even other FrameBuffer's. It is useful + when generating output for displays. + + For example:: + + import framebuf + + # FrameBuffer needs 2 bytes for every RGB565 pixel + fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565) + + fbuf.fill(0) + fbuf.text('MicroPython!', 0, 0, 0xffff) + fbuf.hline(0, 9, 96, 0xffff) + """ + def poly(self, x, y, coords, c, f: Union[bool, int] = False, /) -> Incomplete: + """ + Given a list of coordinates, draw an arbitrary (convex or concave) closed + polygon at the given x, y location using the given color. + + The *coords* must be specified as a :mod:`array` of integers, e.g. + ``array('h', [x0, y0, x1, y1, ... xn, yn])``. + + The optional *f* parameter can be set to ``True`` to fill the polygon. + Otherwise just a one pixel outline is drawn. + """ + ... + def vline(self, x: int, y: int, h: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + + @overload + def pixel(self, x: int, y: int, /) -> int: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + + @overload + def pixel(self, x: int, y: int, c: int, /) -> None: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + def text(self, s: str, x: int, y: int, c: int = 1, /) -> None: + """ + Write text to the FrameBuffer using the coordinates as the upper-left + corner of the text. The color of the text can be defined by the optional + argument but is otherwise a default value of 1. All characters have + dimensions of 8x8 pixels and there is currently no way to change the font. + """ + ... + def rect(self, x: int, y: int, w: int, h: int, c: int, f: Union[bool, int] = False, /) -> None: + """ + Draw a rectangle at the given location, size and color. + + The optional *f* parameter can be set to ``True`` to fill the rectangle. + Otherwise just a one pixel outline is drawn. + """ + ... + def scroll(self, xstep: int, ystep: int, /) -> None: + """ + Shift the contents of the FrameBuffer by the given vector. This may + leave a footprint of the previous colors in the FrameBuffer. + """ + ... + def ellipse(self, x, y, xr, yr, c, f: Union[bool, int] = False, m: Optional[int] = None) -> None: + """ + Draw an ellipse at the given location. Radii *xr* and *yr* define the + geometry; equal values cause a circle to be drawn. The *c* parameter + defines the color. + + The optional *f* parameter can be set to ``True`` to fill the ellipse. + Otherwise just a one pixel outline is drawn. + + The optional *m* parameter enables drawing to be restricted to certain + quadrants of the ellipse. The LS four bits determine which quadrants are + to be drawn, with bit 0 specifying Q1, b1 Q2, b2 Q3 and b3 Q4. Quadrants + are numbered counterclockwise with Q1 being top right. + """ + ... + def line(self, x1: int, y1: int, x2: int, y2: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def blit( + self, + fbuf: FrameBuffer, + x: int, + y: int, + key: int = -1, + palette: Optional[bytes] = None, + /, + ) -> None: + """ + Draw another FrameBuffer on top of the current one at the given coordinates. + If *key* is specified then it should be a color integer and the + corresponding color will be considered transparent: all pixels with that + color value will not be drawn. (If the *palette* is specified then the *key* + is compared to the value from *palette*, not to the value directly from + *fbuf*.) + + *fbuf* can be another FrameBuffer instance, or a tuple or list of the form:: + + (buffer, width, height, format) + + or:: + + (buffer, width, height, format, stride) + + This matches the signature of the FrameBuffer constructor, and the elements + of the tuple/list are the same as the arguments to the constructor except that + the *buffer* here can be read-only. + + The *palette* argument enables blitting between FrameBuffers with differing + formats. Typical usage is to render a monochrome or grayscale glyph/icon to + a color display. The *palette* is a FrameBuffer instance whose format is + that of the current FrameBuffer. The *palette* height is one pixel and its + pixel width is the number of colors in the source FrameBuffer. The *palette* + for an N-bit source needs 2**N pixels; the *palette* for a monochrome source + would have 2 pixels representing background and foreground colors. The + application assigns a color to each pixel in the *palette*. The color of the + current pixel will be that of that *palette* pixel whose x position is the + color of the corresponding source pixel. + """ + ... + def hline(self, x: int, y: int, w: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def fill(self, c: int, /) -> None: + """ + Fill the entire FrameBuffer with the specified color. + """ + ... + def fill_rect(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + buffer: AnyWritableBuf, + width: int, + height: int, + format: int, + stride: int = ..., + /, + ) -> None: + """ + Construct a FrameBuffer object. The parameters are: + + - *buffer* is an object with a buffer protocol which must be large + enough to contain every pixel defined by the width, height and + format of the FrameBuffer. + - *width* is the width of the FrameBuffer in pixels + - *height* is the height of the FrameBuffer in pixels + - *format* specifies the type of pixel used in the FrameBuffer; + permissible values are listed under Constants below. These set the + number of bits used to encode a color value and the layout of these + bits in *buffer*. + Where a color value c is passed to a method, c is a small integer + with an encoding that is dependent on the format of the FrameBuffer. + - *stride* is the number of pixels between each horizontal line + of pixels in the FrameBuffer. This defaults to *width* but may + need adjustments when implementing a FrameBuffer within another + larger FrameBuffer or screen. The *buffer* size must accommodate + an increased step size. + + One must specify valid *buffer*, *width*, *height*, *format* and + optionally *stride*. Invalid *buffer* size or dimensions may lead to + unexpected errors. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/gc.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/gc.pyi new file mode 100644 index 000000000..497082f3a --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/gc.pyi @@ -0,0 +1,112 @@ +""" +Control the garbage collector. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/gc.html + +CPython module: :mod:`python:gc` https://docs.python.org/3/library/gc.html . + +--- +Module: 'gc' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def mem_alloc() -> int: + """ + Return the number of bytes of heap RAM that are allocated by Python code. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +def isenabled(*args, **kwargs) -> Incomplete: ... +def mem_free() -> int: + """ + Return the number of bytes of heap RAM that is available for Python + code to allocate, or -1 if this amount is not known. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +@overload +def threshold() -> int: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +@overload +def threshold(amount: int) -> None: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +def collect() -> None: + """ + Run a garbage collection. + """ + ... + +def enable() -> None: + """ + Enable automatic garbage collection. + """ + ... + +def disable() -> None: + """ + Disable automatic garbage collection. Heap memory can still be allocated, + and garbage collection can still be initiated manually using :meth:`gc.collect`. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/hashlib.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/hashlib.pyi new file mode 100644 index 000000000..ef2d98ac0 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/hashlib.pyi @@ -0,0 +1,116 @@ +""" +Hashing algorithms. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/hashlib.html + +CPython module: :mod:`python:hashlib` https://docs.python.org/3/library/hashlib.html . + +This module implements binary data hashing algorithms. The exact inventory +of available algorithms depends on a board. Among the algorithms which may +be implemented: + +* SHA256 - The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + +* SHA1 - A previous generation algorithm. Not recommended for new usages, + but SHA1 is a part of number of Internet standards and existing + applications, so boards targeting network connectivity and + interoperability will try to provide this. + +* MD5 - A legacy algorithm, not considered cryptographically secure. Only + selected boards, targeting interoperability with legacy applications, + will offer this. + +--- +Module: 'hashlib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, _Hash +from typing import NoReturn, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated + +class sha1(_Hash): + """ + A previous generation algorithm. Not recommended for new usages, + but SHA1 is a part of number of Internet standards and existing + applications, so boards targeting network connectivity and + interoperability will try to provide this. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + +class sha256(_Hash): + """ + The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + +class md5(_Hash): + """ + A legacy algorithm, not considered cryptographically secure. Only + selected boards, targeting interoperability with legacy applications, + will offer this. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, data: AnyReadableBuf = ..., /) -> None: + """ + Create an MD5 hasher object and optionally feed ``data`` into it. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/heapq.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/heapq.pyi new file mode 100644 index 000000000..e861ff86b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/heapq.pyi @@ -0,0 +1,46 @@ +""" +Heap queue algorithm. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/heapq.html + +CPython module: :mod:`python:heapq` https://docs.python.org/3/library/heapq.html . + +This module implements the +`min heap queue algorithm `_. + +A heap queue is essentially a list that has its elements stored in such a way +that the first item of the list is always the smallest. + +--- +Module: 'heapq' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +def heappop(heap: list[_T], /) -> _T: + """ + Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if + ``heap`` is empty. + + The returned item will be the smallest item in the ``heap``. + """ + ... + +def heappush(heap: list[_T], item: _T, /) -> None: + """ + Push the ``item`` onto the ``heap``. + """ + ... + +def heapify(x: list[Any], /) -> None: + """ + Convert the list ``x`` into a heap. This is an in-place operation. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/lwip.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/lwip.pyi new file mode 100644 index 000000000..74afeef79 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/lwip.pyi @@ -0,0 +1,51 @@ +""" +Module: 'lwip' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +SOCK_RAW: Final[int] = 3 +SOCK_STREAM: Final[int] = 1 +SOCK_DGRAM: Final[int] = 2 +MSG_PEEK: Final[int] = 1 +SO_REUSEADDR: Final[int] = 4 +SOL_SOCKET: Final[int] = 1 +SO_BROADCAST: Final[int] = 32 +TCP_NODELAY: Final[int] = 64 +AF_INET6: Final[int] = 10 +IPPROTO_IP: Final[int] = 0 +AF_INET: Final[int] = 2 +MSG_DONTWAIT: Final[int] = 2 +IP_DROP_MEMBERSHIP: Final[int] = 1025 +IPPROTO_TCP: Final[int] = 6 +IP_ADD_MEMBERSHIP: Final[int] = 1024 + +def reset(*args, **kwargs) -> Incomplete: ... +def print_pcbs(*args, **kwargs) -> Incomplete: ... +def getaddrinfo(*args, **kwargs) -> Incomplete: ... +def callback(*args, **kwargs) -> Incomplete: ... + +class socket: + def recvfrom(self, *args, **kwargs) -> Incomplete: ... + def recv(self, *args, **kwargs) -> Incomplete: ... + def makefile(self, *args, **kwargs) -> Incomplete: ... + def listen(self, *args, **kwargs) -> Incomplete: ... + def settimeout(self, *args, **kwargs) -> Incomplete: ... + def sendall(self, *args, **kwargs) -> Incomplete: ... + def setsockopt(self, *args, **kwargs) -> Incomplete: ... + def setblocking(self, *args, **kwargs) -> Incomplete: ... + def sendto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def connect(self, *args, **kwargs) -> Incomplete: ... + def send(self, *args, **kwargs) -> Incomplete: ... + def bind(self, *args, **kwargs) -> Incomplete: ... + def accept(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/machine.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/machine.pyi new file mode 100644 index 000000000..0baf2cdb9 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/machine.pyi @@ -0,0 +1,3251 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. + +--- +Module: 'machine' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import NoReturn, Union, List, Sequence, Optional, Callable, Tuple, overload, Any, Final +from _typeshed import Incomplete +from typing_extensions import deprecated, Awaitable, TypeAlias, TypeVar +from _mpy_shed import mp_available, _IRQ, AnyReadableBuf, AnyWritableBuf +from vfs import AbstractBlockDev + +SOFT_RESET: Final[int] = 5 +"""Reset causes.""" +PWRON_RESET: Final[int] = 1 +"""Reset causes.""" +WDT_RESET: Final[int] = 3 +"""Reset causes.""" +ID_T: TypeAlias = int | str +ATTN_0DB: int = ... +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +HARD_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +def unique_id() -> bytes: + """ + Returns a byte string with a unique identifier of a board/SoC. It will vary + from a board/SoC instance to another, if underlying hardware allows. Length + varies by hardware (so use substring of a full value if you expect a short + ID). In some MicroPython ports, ID corresponds to the network MAC address. + """ + ... + +def disable_irq() -> _IRQ_STATE: + """ + Disable interrupt requests. + Returns the previous IRQ state which should be considered an opaque value. + This return value should be passed to the `enable_irq()` function to restore + interrupts to their original state, before `disable_irq()` was called. + """ + ... + +def dht_readinto(*args, **kwargs) -> Incomplete: ... +def bitstream(pin, encoding, timing, data, /) -> Incomplete: + """ + Transmits *data* by bit-banging the specified *pin*. The *encoding* argument + specifies how the bits are encoded, and *timing* is an encoding-specific timing + specification. + + The supported encodings are: + + - ``0`` for "high low" pulse duration modulation. This will transmit 0 and + 1 bits as timed pulses, starting with the most significant bit. + The *timing* must be a four-tuple of nanoseconds in the format + ``(high_time_0, low_time_0, high_time_1, low_time_1)``. For example, + ``(400, 850, 800, 450)`` is the timing specification for WS2812 RGB LEDs + at 800kHz. + + The accuracy of the timing varies between ports. On Cortex M0 at 48MHz, it is + at best +/- 120ns, however on faster MCUs (ESP8266, ESP32, STM32, Pyboard), it + will be closer to +/-30ns. + + ``Note:`` For controlling WS2812 / NeoPixel strips, see the :mod:`neopixel` + module for a higher-level API. + """ + ... + +def bootloader(value: Optional[Any] = None) -> None: + """ + Reset the device and enter its bootloader. This is typically used to put the + device into a state where it can be programmed with new firmware. + + Some ports support passing in an optional *value* argument which can control + which bootloader to enter, what to pass to it, or other things. + """ + ... + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +def enable_irq(state: _IRQ_STATE, /) -> None: + """ + Re-enable interrupt requests. + The *state* parameter should be the value that was returned from the most + recent call to the `disable_irq()` function. + """ + ... + +def reset_cause() -> int: + """ + Get the reset cause. See :ref:`constants ` for the possible return values. + """ + ... + +def soft_reset() -> NoReturn: + """ + Performs a :ref:`soft reset ` of the interpreter, deleting all + Python objects and resetting the Python heap. + """ + ... + +def time_pulse_us(pin: Pin, pulse_level: int, timeout_us: int = 1_000_000, /) -> int: + """ + Time a pulse on the given *pin*, and return the duration of the pulse in + microseconds. The *pulse_level* argument should be 0 to time a low pulse + or 1 to time a high pulse. + + If the current input value of the pin is different to *pulse_level*, + the function first (*) waits until the pin input becomes equal to *pulse_level*, + then (**) times the duration that the pin is equal to *pulse_level*. + If the pin is already equal to *pulse_level* then timing starts straight away. + + The function will return -2 if there was timeout waiting for condition marked + (*) above, and -1 if there was timeout during the main measurement, marked (**) + above. The timeout is the same for both cases and given by *timeout_us* (which + is in microseconds). + """ + ... + +def reset() -> NoReturn: + """ + :ref:`Hard resets ` the device in a manner similar to pushing the + external RESET button. + """ + ... + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +def idle() -> None: + """ + Gates the clock to the CPU, useful to reduce power consumption at any time + during short or long periods. Peripherals continue working and execution + resumes as soon as any interrupt is triggered, or at most one millisecond + after the CPU was paused. + + It is recommended to call this function inside any tight loop that is + continuously checking for an external change (i.e. polling). This will reduce + power consumption without significantly impacting performance. To reduce + power consumption further then see the :func:`lightsleep`, + :func:`time.sleep()` and :func:`time.sleep_ms()` functions. + """ + ... + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +mem8: Incomplete ## = <8-bit memory> +"""Read/write 8 bits of memory.""" +mem32: Incomplete ## = <32-bit memory> +"""\ +Read/write 32 bits of memory. + +Use subscript notation ``[...]`` to index these objects with the address of +interest. Note that the address is the byte address, regardless of the size of +memory being accessed. + +Example use (registers are specific to an stm32 microcontroller): +""" +mem16: Incomplete ## = <16-bit memory> +"""Read/write 16 bits of memory.""" + +class LED: + def on(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class PWM: + """ + This class provides pulse width modulation output. + + Example usage:: + + from machine import PWM + + pwm = PWM(pin) # create a PWM object on a pin + pwm.duty_u16(32768) # set duty to 50% + + # reinitialise with a period of 200us, duty of 5us + pwm.init(freq=5000, duty_ns=5000) + + pwm.duty_ns(3000) # set pulse width to 3us + + pwm.deinit() + + + Limitations of PWM + ------------------ + + * Not all frequencies can be generated with absolute accuracy due to + the discrete nature of the computing hardware. Typically the PWM frequency + is obtained by dividing some integer base frequency by an integer divider. + For example, if the base frequency is 80MHz and the required PWM frequency is + 300kHz the divider must be a non-integer number 80000000 / 300000 = 266.67. + After rounding the divider is set to 267 and the PWM frequency will be + 80000000 / 267 = 299625.5 Hz, not 300kHz. If the divider is set to 266 then + the PWM frequency will be 80000000 / 266 = 300751.9 Hz, but again not 300kHz. + + * The duty cycle has the same discrete nature and its absolute accuracy is not + achievable. On most hardware platforms the duty will be applied at the next + frequency period. Therefore, you should wait more than "1/frequency" before + measuring the duty. + + * The frequency and the duty cycle resolution are usually interdependent. + The higher the PWM frequency the lower the duty resolution which is available, + and vice versa. For example, a 300kHz PWM frequency can have a duty cycle + resolution of 8 bit, not 16-bit as may be expected. In this case, the lowest + 8 bits of *duty_u16* are insignificant. So:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2) + + and:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255) + + will generate PWM with the same 50% duty cycle. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + def init(self, *, freq: int = ..., duty_u16: int = ..., duty_ns: int = ...) -> None: + """ + Modify settings for the PWM object. See the above constructor for details + about the parameters. + """ + ... + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + def deinit(self) -> None: + """ + Disable the PWM output. + """ + ... + def __init__( + self, + dest: PinLike, + /, + *, + freq: int = ..., + duty_u16: int = ..., + duty_ns: int = ..., + ) -> None: + """ + Construct and return a new PWM object using the following parameters: + + - *dest* is the entity on which the PWM is output, which is usually a + :ref:`machine.Pin ` object, but a port may allow other values, + like integers. + - *freq* should be an integer which sets the frequency in Hz for the + PWM cycle. + - *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``. + - *duty_ns* sets the pulse width in nanoseconds. + + Setting *freq* may affect other PWM objects if the objects share the same + underlying PWM generator (this is hardware specific). + Only one of *duty_u16* and *duty_ns* should be specified at a time. + """ + +class I2S: + """ + I2S is a synchronous serial protocol used to connect digital audio devices. + At the physical level, a bus consists of 3 lines: SCK, WS, SD. + The I2S class supports controller operation. Peripheral operation is not supported. + + The I2S class is currently available as a Technical Preview. During the preview period, feedback from + users is encouraged. Based on this feedback, the I2S class API and implementation may be changed. + + I2S objects can be created and initialized using:: + + from machine import I2S + from machine import Pin + + # ESP32 + sck_pin = Pin(14) # Serial clock output + ws_pin = Pin(13) # Word clock output + sd_pin = Pin(12) # Serial data output + + or + + # PyBoards + sck_pin = Pin("Y6") # Serial clock output + ws_pin = Pin("Y5") # Word clock output + sd_pin = Pin("Y8") # Serial data output + + audio_out = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.TX, + bits=16, + format=I2S.MONO, + rate=44100, + ibuf=20000) + + audio_in = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.RX, + bits=32, + format=I2S.STEREO, + rate=22050, + ibuf=20000) + + 3 modes of operation are supported: + - blocking + - non-blocking + - uasyncio + + blocking:: + + num_written = audio_out.write(buf) # blocks until buf emptied + + num_read = audio_in.readinto(buf) # blocks until buf filled + + non-blocking:: + + audio_out.irq(i2s_callback) # i2s_callback is called when buf is emptied + num_written = audio_out.write(buf) # returns immediately + + audio_in.irq(i2s_callback) # i2s_callback is called when buf is filled + num_read = audio_in.readinto(buf) # returns immediately + + uasyncio:: + + swriter = uasyncio.StreamWriter(audio_out) + swriter.write(buf) + await swriter.drain() + + sreader = uasyncio.StreamReader(audio_in) + num_read = await sreader.readinto(buf) + """ + + RX: Final[int] = 0 + """for initialising the I2S bus ``mode`` to receive""" + MONO: Final[int] = 0 + """for initialising the I2S bus ``format`` to mono""" + STEREO: Final[int] = 1 + """for initialising the I2S bus ``format`` to stereo""" + TX: Final[int] = 1 + """for initialising the I2S bus ``mode`` to transmit""" + @staticmethod + def shift( + buf: AnyWritableBuf, + bits: int, + shift: int, + /, + ) -> None: + """ + bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample. + Positive for left shift, negative for right shift. + Typically used for volume control. Each bit shift changes sample volume by 6dB. + """ + ... + def init( + self, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + see Constructor for argument descriptions + """ + ... + def irq( + self, + handler: Callable[[Any], None], + /, + ) -> None: + """ + Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method). + Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation. + ``handler`` is called in the context of the MicroPython scheduler. + """ + ... + def readinto( + self, + buf: AnyWritableBuf, + /, + ) -> int: + """ + Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the left channel sample data is used. + Returns number of bytes read + """ + ... + def deinit(self) -> None: + """ + Deinitialize the I2S bus + """ + ... + def write( + self, + buf: AnyReadableBuf, + /, + ) -> int: + """ + Write audio samples contained in ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the sample data is written to both the right and left channels. + Returns number of bytes written + """ + ... + def __init__( + self, + id: ID_T, + /, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + Construct an I2S object of the given id: + + - ``id`` identifies a particular I2S bus. + + ``id`` is board and port specific: + + - PYBv1.0/v1.1: has one I2S bus with id=2. + - PYBD-SFxW: has two I2S buses with id=1 and id=2. + - ESP32: has two I2S buses with id=0 and id=1. + + Keyword-only parameters that are supported on all ports: + + - ``sck`` is a pin object for the serial clock line + - ``ws`` is a pin object for the word select line + - ``sd`` is a pin object for the serial data line + - ``mode`` specifies receive or transmit + - ``bits`` specifies sample size (bits), 16 or 32 + - ``format`` specifies channel format, STEREO or MONO + - ``rate`` specifies audio sampling rate (samples/s) + - ``ibuf`` specifies internal buffer length (bytes) + + For all ports, DMA runs continuously in the background and allows user applications to perform other operations while + sample data is transfered between the internal buffer and the I2S peripheral unit. + Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations + before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method). + """ + +class ADC: + """ + The ADC class provides an interface to analog-to-digital convertors, and + represents a single endpoint that can sample a continuous voltage and + convert it to a discretised value. + + Example usage:: + + import machine + + adc = machine.ADC(pin) # create an ADC object acting on a pin + val = adc.read_u16() # read a raw analog value in the range 0-65535 + """ + + VREF: int = ... + CORE_VREF: int = ... + CORE_VBAT: int = ... + CORE_TEMP: int = ... + ATTN_0DB: int = 0 + ATTN_2_5DB: int = 1 + ATTN_6DB: int = 2 + ATTN_11DB: int = 3 + WIDTH_9BIT: int = 9 + WIDTH_10BIT: int = 10 + WIDTH_11BIT: int = 11 + WIDTH_12BIT: int = 12 + def read_uv(self) -> int: + """ + Take an analog reading and return an integer value with units of + microvolts. It is up to the particular port whether or not this value + is calibrated, and how calibration is done. + """ + ... + def read_u16(self) -> int: + """ + Take an analog reading and return an integer in the range 0-65535. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 65535. + """ + ... + def __init__(self, pin: PinLike, *, atten=ATTN_0DB) -> None: + """ + Access the ADC associated with a source identified by *id*. This + *id* may be an integer (usually specifying a channel number), a + :ref:`Pin ` object, or other value supported by the + underlying machine. + .. note:: + + WiPy has a custom implementation of ADC, see ADCWiPy for details. + + on ESP32 : `atten` specifies the attenuation level for the ADC input. + """ + + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class I2C: + """ + 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. + + I2C objects are created attached to a specific bus. They can be initialised + when created, or initialised later on. + + Printing the I2C object gives you information about its configuration. + + Both hardware and software I2C implementations exist via the + :ref:`machine.I2C ` and `machine.SoftI2C` classes. Hardware I2C uses + underlying hardware support of the system to perform the reads/writes and is + usually efficient and fast but may have restrictions on which pins can be used. + Software I2C is implemented by bit-banging and can be used on any pin but is not + as efficient. These classes have the same methods available and differ primarily + in the way they are constructed. + + Example usage:: + + from machine import I2C + + i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz + # depending on the port, extra parameters may be required + # to select the peripheral and/or pins to use + + i2c.scan() # scan for peripherals, returning a list of 7-bit addresses + + i2c.writeto(42, b'123') # write 3 bytes to peripheral with 7-bit address 42 + i2c.readfrom(42, 4) # read 4 bytes from peripheral with 7-bit address 42 + + i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of peripheral 42, + # starting at memory-address 8 in the peripheral + i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42 + # starting at address 2 in the peripheral + """ + def readfrom_mem_into(self, addr: int, memaddr: int, buf: AnyWritableBuf, /, *, addrsize: int = 8) -> None: + """ + Read into *buf* from the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. The number of bytes read is the + length of *buf*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def readfrom_into(self, addr: int, buf: AnyWritableBuf, stop: bool = True, /) -> None: + """ + Read into *buf* from the peripheral specified by *addr*. + The number of bytes read will be the length of *buf*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + + The method returns ``None``. + """ + ... + def readfrom_mem(self, addr: int, memaddr: int, nbytes: int, /, *, addrsize: int = 8) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr* starting from the memory + address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits. + Returns a `bytes` object with the data read. + """ + ... + def writeto_mem(self, addr: int, memaddr: int, buf: AnyReadableBuf, /, *, addrsize: int = 8) -> None: + """ + Write *buf* to the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def scan(self) -> List: + """ + 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 write bit) is sent on the bus. + """ + ... + def writeto(self, addr: int, buf: AnyReadableBuf, stop: bool = True, /) -> int: + """ + Write the bytes from *buf* to the peripheral specified by *addr*. If a + NACK is received following the write of a byte from *buf* then the + remaining bytes are not sent. If *stop* is true then a STOP condition is + generated at the end of the transfer, even if a NACK is received. + The function returns the number of ACKs that were received. + """ + ... + def writevto(self, addr: int, vector: Sequence[AnyReadableBuf], stop: bool = True, /) -> int: + """ + Write the bytes contained in *vector* to the peripheral specified by *addr*. + *vector* should be a tuple or list of objects with the buffer protocol. + The *addr* is sent once and then the bytes from each object in *vector* + are written out sequentially. The objects in *vector* may be zero bytes + in length in which case they don't contribute to the output. + + If a NACK is received following the write of a byte from one of the + objects in *vector* then the remaining bytes, and any remaining objects, + are not sent. If *stop* is true then a STOP condition is generated at + the end of the transfer, even if a NACK is received. The function + returns the number of ACKs that were received. + """ + ... + def start(self) -> None: + """ + Generate a START condition on the bus (SDA transitions to low while SCL is high). + """ + ... + def readfrom(self, addr: int, nbytes: int, stop: bool = True, /) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + Returns a `bytes` object with the data read. + """ + ... + def readinto(self, buf: AnyWritableBuf, nack: bool = True, /) -> None: + """ + Reads bytes from the bus and stores them into *buf*. The number of bytes + read is the length of *buf*. An ACK will be sent on the bus after + receiving all but the last byte. After the last byte is received, if *nack* + is true then a NACK will be sent, otherwise an ACK will be sent (and in this + case the peripheral assumes more bytes are going to be read in a later call). + """ + ... + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + def stop(self) -> None: + """ + Generate a STOP condition on the bus (SDA transitions to high while SCL is high). + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes from *buf* to the bus. Checks that an ACK is received + after each byte and stops transmitting the remaining bytes if a NACK is + received. The function returns the number of ACKs that were received. + """ + ... + + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class I2CTarget: + """ + Construct and return a new I2CTarget object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values depend on the + particular port/board. Some ports have a default in which case this parameter + can be omitted. + - *addr* is the I2C address of the target. + - *addrsize* is the number of bits in the I2C target address. Valid values + are 7 and 10. + - *mem* is an object with the buffer protocol that is writable. If not + specified then there is no backing memory and data must be read/written + using the :meth:`I2CTarget.readinto` and :meth:`I2CTarget.write` methods. + - *mem_addrsize* is the number of bits in the memory address. Valid values + are 0, 8, 16, 24 and 32. + - *scl* is a pin object specifying the pin to use for SCL. + - *sda* is a pin object specifying the pin to use for SDA. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + IRQ_END_READ: Final[int] = 16 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_WRITE: Final[int] = 2 + """IRQ trigger sources.""" + IRQ_END_WRITE: Final[int] = 32 + """IRQ trigger sources.""" + IRQ_READ_REQ: Final[int] = 4 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_READ: Final[int] = 1 + """IRQ trigger sources.""" + IRQ_WRITE_REQ: Final[int] = 8 + """IRQ trigger sources.""" + def deinit(self) -> Incomplete: + """ + Deinitialise the I2C target. After this method is called the hardware will no + longer respond to requests on the I2C bus, and no other methods can be called. + """ + ... + def irq(self, handler=None, trigger=IRQ_END_READ | IRQ_END_WRITE, hard=False) -> Incomplete: + """ + Configure an IRQ *handler* to be called when an event occurs. The possible events are + given by the following constants, which can be or'd together and passed to the *trigger* + argument: + + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a read transaction. + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a write transaction. + - ``IRQ_READ_REQ`` indicates that the controller is requesting data, and this + request must be satisfied by calling `I2CTarget.write` with the data to be + passed back to the controller. + - ``IRQ_WRITE_REQ`` indicates that the controller has written data, and the + data must be read by calling `I2CTarget.readinto`. + - ``IRQ_END_READ`` indicates that the controller has finished a read transaction. + - ``IRQ_END_WRITE`` indicates that the controller has finished a write transaction. + + Not all triggers are available on all ports. If a port has the constant then that + event is available. + + Note the following restrictions: + + - ``IRQ_ADDR_MATCH_READ``, ``IRQ_ADDR_MATCH_READ``, ``IRQ_READ_REQ`` and + ``IRQ_WRITE_REQ`` must be handled by a hard IRQ callback (with the *hard* argument + set to ``True``). This is because these events have very strict timing requirements + and must usually be satisfied synchronously with the hardware event. + + - ``IRQ_END_READ`` and ``IRQ_END_WRITE`` may be handled by either a soft or hard + IRQ callback (although note that all events must be registered with the same handler, + so if any events need a hard callback then all events must be hard). + + - If a memory buffer has been supplied in the constructor then ``IRQ_END_WRITE`` + is not emitted for the transaction that writes the memory address. This is to + allow ``IRQ_END_READ`` and ``IRQ_END_WRITE`` to function correctly as soft IRQ + callbacks, where the IRQ handler may be called quite some time after the actual + hardware event. + """ + ... + def write(self, buf) -> int: + """ + Write out the bytes from the given buffer, to be passed to the I2C controller + after it sends a read request. Returns the number of bytes written. Most ports + only accept one byte at a time to this method. + """ + ... + def readinto(self, buf) -> int: + """ + Read into the given buffer any pending bytes written by the I2C controller. + Returns the number of bytes read. + """ + ... + def __init__(self, id, addr, *, addrsize=7, mem=None, mem_addrsize=8, scl=None, sda=None) -> None: ... + +class UART: + """ + UART implements the standard UART/USART duplex serial communications protocol. At + the physical level it consists of 2 lines: RX and TX. The unit of communication + is a character (not to be confused with a string character) which can be 8 or 9 + bits wide. + + UART objects can be created and initialised using:: + + from machine import UART + + uart = UART(1, 9600) # init with given baudrate + uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters + + Supported parameters differ on a board: + + Pyboard: Bits can be 7, 8 or 9. Stop can be 1 or 2. With *parity=None*, + only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits + are supported. + + WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2. + + A UART object acts like a `stream` object and reading and writing is done + using the standard stream methods:: + + uart.read(10) # read 10 characters, returns a bytes object + uart.read() # read all available characters + uart.readline() # read a line + uart.readinto(buf) # read and store into the given buffer + uart.write('abc') # write the 3 characters + """ + + INV_TX: Final[int] = 1 + INV_RX: Final[int] = 2 + CTS: Final[int] = 2 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RXIDLE: Final[int] = 1 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + IRQ_TXIDLE: Final[int] = 2 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + RTS: Final[int] = 1 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RX: Incomplete + IRQ_BREAK: Incomplete + IDLE: int = ... + def irq( + self, + handler: Callable[[UART], None] | None = None, + trigger: int = 0, + hard: bool = False, + /, + ) -> _IRQ: + """ + Configure an interrupt handler to be called when a UART event occurs. + + The arguments are: + + - *handler* is an optional function to be called when the interrupt event + triggers. The handler must take exactly one argument which is the + ``UART`` instance. + + - *trigger* configures the event(s) which can generate an interrupt. + Possible values are a mask of one or more of the following: + + - ``UART.IRQ_RXIDLE`` interrupt after receiving at least one character + and then the RX line goes idle. + - ``UART.IRQ_RX`` interrupt after each received character. + - ``UART.IRQ_TXIDLE`` interrupt after or while the last character(s) of + a message are or have been sent. + - ``UART.IRQ_BREAK`` interrupt when a break state is detected at RX + + - *hard* if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + + Returns an irq object. + + Due to limitations of the hardware not all trigger events are available on all ports. + """ + ... + def sendbreak(self) -> None: + """ + Send a break condition on the bus. This drives the bus low for a duration + longer than required for a normal transmission of a character. + """ + ... + def deinit(self) -> None: + """ + Turn off the UART bus. + + .. note:: + You will not be able to call ``init()`` on the object after ``deinit()``. + A new instance needs to be created in that case. + """ + ... + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + def flush(self) -> Incomplete: + """ + Waits until all data has been sent. In case of a timeout, an exception is raised. The timeout + duration depends on the tx buffer size and the baud rate. Unless flow control is enabled, a timeout + should not occur. + + .. note:: + + For the esp8266 and nrf ports the call returns while the last byte is sent. + If required, a one character wait time has to be added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + def txdone(self) -> bool: + """ + Tells whether all data has been sent or no data transfer is happening. In this case, + it returns ``True``. If a data transmission is ongoing it returns ``False``. + + .. note:: + + For the esp8266 and nrf ports the call may return ``True`` even if the last byte + of a transfer is still being sent. If required, a one character wait time has to be + added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read without + blocking. It will return 0 if there are no characters available and a positive + number if there are characters. The method may return 1 even if there is more + than one character available for reading. + + For more sophisticated querying of available characters use select.poll:: + + poll = select.poll() + poll.register(uart, select.POLLIN) + poll.poll(timeout) + """ + ... + def write(self, buf: AnyReadableBuf, /) -> Union[int, None]: + """ + Write the buffer of bytes to the bus. + + Return value: number of bytes written or ``None`` on timeout. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + def readline(self) -> Union[str, None]: + """ + Read a line, ending in a newline character. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: the line read or ``None`` on timeout. + """ + ... + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + +class SoftI2C(I2C): + """ + Construct a new software I2C object. The parameters are: + + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + - *timeout* is the maximum time in microseconds to wait for clock + stretching (SCL held low by another device on the bus), after + which an ``OSError(ETIMEDOUT)`` exception is raised. + """ + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, scl, sda, *, freq=400000, timeout=50000) -> None: ... + +class SoftSPI(SPI): + """ + Construct a new software SPI object. Additional parameters must be + given, usually at least *sck*, *mosi* and *miso*, and these are used + to initialise the bus. See `SPI.init` for a description of the parameters. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + baudrate=500000, + *, + polarity=0, + phase=0, + bits=8, + firstbit=MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: ... + +class Timer: + """ + Hardware timers deal with timing of periods and events. Timers are perhaps + the most flexible and heterogeneous kind of hardware in MCUs and SoCs, + differently greatly from a model to a model. MicroPython's Timer class + defines a baseline operation of executing a callback with a given period + (or once after some delay), and allow specific boards to define more + non-standard behaviour (which thus won't be portable to other boards). + + See discussion of :ref:`important constraints ` on + Timer callbacks. + + .. note:: + + Memory can't be allocated inside irq handlers (an interrupt) and so + exceptions raised within a handler don't give much information. See + :func:`micropython.alloc_emergency_exception_buf` for how to get around this + limitation. + + If you are using a WiPy board please refer to :ref:`machine.TimerWiPy ` + instead of this class. + """ + + PERIODIC: Final[int] = 2 + """Timer operating mode.""" + ONE_SHOT: Final[int] = 1 + """Timer operating mode.""" + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + def deinit(self) -> None: + """ + Deinitialises the timer. Stops the timer, and disables the timer peripheral. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + +class WDT: + """ + The WDT 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 machine import WDT + wdt = WDT(timeout=2000) # enable it with a timeout of 2s + wdt.feed() + + Availability of this class: pyboard, WiPy, esp8266, esp32. + """ + def timeout_ms(self, *args, **kwargs) -> Incomplete: ... + def feed(self) -> None: + """ + Feed the WDT to prevent it from resetting the system. The application + should place this call in a sensible place ensuring that the WDT is + only fed after verifying that everything is functioning correctly. + """ + ... + def __init__(self, *, id: int = 0, timeout: int = 5000) -> None: + """ + Create a WDT object and start it. The timeout must be given in milliseconds. + Once it is running the timeout cannot be changed and the WDT cannot be stopped either. + + Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout + cannot be specified, it is determined by the underlying system. + """ + +class Pin: + """ + A pin object is used to control I/O pins (also known as GPIO - general-purpose + input/output). Pin objects are commonly associated with a physical pin that can + drive an output voltage and read input voltages. The pin class has methods to set the mode of + the pin (IN, OUT, etc) and methods to get and set the digital logic level. + For analog control of a pin, see the :class:`ADC` class. + + A pin object is constructed by using an identifier which unambiguously + specifies a certain I/O pin. The allowed forms of the identifier and the + physical pin that the identifier maps to are port-specific. Possibilities + for the identifier are an integer, a string or a tuple with port and pin + number. + + Usage Model:: + + from machine import Pin + + # create an output pin on pin #0 + p0 = Pin(0, Pin.OUT) + + # set the value low then high + p0.value(0) + p0.value(1) + + # create an input pin on pin #2, with a pull up resistor + p2 = Pin(2, Pin.IN, Pin.PULL_UP) + + # read and print the pin value + print(p2.value()) + + # reconfigure pin #0 in input mode with a pull down resistor + p0.init(p0.IN, p0.PULL_DOWN) + + # configure an irq callback + p0.irq(lambda p:print(p)) + """ + + OPEN_DRAIN: Final[int] = 2 + """Selects the pin mode.""" + IRQ_RISING: Final[int] = 1 + """Selects the IRQ trigger type.""" + IRQ_FALLING: Final[int] = 2 + """Selects the IRQ trigger type.""" + IN: Final[int] = 0 + """Selects the pin mode.""" + PULL_UP_22K: Final[int] = 3 + OUT: Final[int] = 1 + """Selects the pin mode.""" + PULL_UP: Final[int] = 2 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_HOLD: Final[int] = 5 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_DOWN: Final[int] = 0 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + DRIVE_2: Final[int] = 3 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_1: Final[int] = 2 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_0: Final[int] = 1 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + PULL_UP_47K: Final[int] = 1 + DRIVE_OFF: Final[int] = 0 + DRIVE_3: Final[int] = 4 + DRIVE_6: Final[int] = 7 + DRIVE_5: Final[int] = 6 + DRIVE_4: Final[int] = 5 + ALT: Incomplete + ALT_OPEN_DRAIN: Incomplete + ANALOG: Incomplete + IRQ_LOW_LEVEL: Incomplete + IRQ_HIGH_LEVEL: Incomplete + def low(self) -> None: + """ + Set pin to "0" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + def irq( + self, + /, + handler: Callable[[Pin], None] | None = None, + trigger: int = (IRQ_FALLING | IRQ_RISING), + *, + priority: int = 1, + wake: int | None = None, + hard: bool = False, + ) -> Callable[..., Incomplete]: + """ + Configure an interrupt handler to be called when the trigger source of the + pin is active. If the pin mode is ``Pin.IN`` then the trigger source is + the external value on the pin. If the pin mode is ``Pin.OUT`` then the + trigger source is the output buffer of the pin. Otherwise, if the pin mode + is ``Pin.OPEN_DRAIN`` then the trigger source is the output buffer for + state '0' and the external pin value for state '1'. + + The arguments are: + + - ``handler`` is an optional function to be called when the interrupt + triggers. The handler must take exactly one argument which is the + ``Pin`` instance. + + - ``trigger`` configures the event which can generate an interrupt. + Possible values are: + + - ``Pin.IRQ_FALLING`` interrupt on falling edge. + - ``Pin.IRQ_RISING`` interrupt on rising edge. + - ``Pin.IRQ_LOW_LEVEL`` interrupt on low level. + - ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level. + + These values can be OR'ed together to trigger on multiple events. + + - ``priority`` sets the priority level of the interrupt. The values it + can take are port-specific, but higher values always represent higher + priorities. + + - ``wake`` selects the power mode in which this interrupt can wake up the + system. It can be ``machine.IDLE``, ``machine.SLEEP`` or ``machine.DEEPSLEEP``. + These values can also be OR'ed together to make a pin generate interrupts in + more than one power mode. + + - ``hard`` if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + Not all ports support this argument. + + This method returns a callback object. + + The following methods are not part of the core Pin API and only implemented on certain ports. + """ + ... + def toggle(self) -> Incomplete: + """ + Toggle output pin from "0" to "1" or vice-versa. + + Availability: cc3200, esp32, esp8266, mimxrt, rp2, samd ports. + """ + ... + def off(self) -> None: + """ + Set pin to "0" output level. + """ + ... + def on(self) -> None: + """ + Set pin to "1" output level. + """ + ... + def init( + self, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Re-initialise the pin using the given parameters. Only those arguments that + are specified will be set. The rest of the pin peripheral state will remain + unchanged. See the constructor documentation for details of the arguments. + + Returns ``None``. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + def high(self) -> None: + """ + Set pin to "1" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + + class cpu: + GPIO_EMC_16: Pin ## = Pin(GPIO_EMC_16) + GPIO_EMC_15: Pin ## = Pin(GPIO_EMC_15) + GPIO_EMC_17: Pin ## = Pin(GPIO_EMC_17) + GPIO_EMC_18: Pin ## = Pin(GPIO_EMC_18) + GPIO_EMC_12: Pin ## = Pin(GPIO_EMC_12) + GPIO_EMC_14: Pin ## = Pin(GPIO_EMC_14) + GPIO_EMC_13: Pin ## = Pin(GPIO_EMC_13) + WAKEUP: Pin ## = Pin(WAKEUP) + GPIO_EMC_24: Pin ## = Pin(GPIO_EMC_24) + GPIO_EMC_23: Pin ## = Pin(GPIO_EMC_23) + GPIO_EMC_25: Pin ## = Pin(GPIO_EMC_25) + GPIO_EMC_19: Pin ## = Pin(GPIO_EMC_19) + GPIO_EMC_20: Pin ## = Pin(GPIO_EMC_20) + GPIO_EMC_22: Pin ## = Pin(GPIO_EMC_22) + GPIO_EMC_21: Pin ## = Pin(GPIO_EMC_21) + GPIO_EMC_01: Pin ## = Pin(GPIO_EMC_01) + GPIO_EMC_00: Pin ## = Pin(GPIO_EMC_00) + GPIO_EMC_02: Pin ## = Pin(GPIO_EMC_02) + GPIO_EMC_03: Pin ## = Pin(GPIO_EMC_03) + GPIO_B1_13: Pin ## = Pin(GPIO_B1_13) + GPIO_B1_15: Pin ## = Pin(GPIO_B1_15) + GPIO_B1_14: Pin ## = Pin(GPIO_B1_14) + GPIO_EMC_11: Pin ## = Pin(GPIO_EMC_11) + GPIO_EMC_09: Pin ## = Pin(GPIO_EMC_09) + GPIO_EMC_08: Pin ## = Pin(GPIO_EMC_08) + GPIO_EMC_10: Pin ## = Pin(GPIO_EMC_10) + GPIO_EMC_04: Pin ## = Pin(GPIO_EMC_04) + GPIO_EMC_05: Pin ## = Pin(GPIO_EMC_05) + GPIO_EMC_07: Pin ## = Pin(GPIO_EMC_07) + GPIO_EMC_06: Pin ## = Pin(GPIO_EMC_06) + GPIO_SD_B1_04: Pin ## = Pin(GPIO_SD_B1_04) + GPIO_SD_B1_03: Pin ## = Pin(GPIO_SD_B1_03) + GPIO_SD_B1_05: Pin ## = Pin(GPIO_SD_B1_05) + GPIO_SD_B1_06: Pin ## = Pin(GPIO_SD_B1_06) + GPIO_SD_B1_00: Pin ## = Pin(GPIO_SD_B1_00) + GPIO_SD_B1_02: Pin ## = Pin(GPIO_SD_B1_02) + GPIO_SD_B1_01: Pin ## = Pin(GPIO_SD_B1_01) + GPIO_EMC_26: Pin ## = Pin(GPIO_EMC_26) + PMIC_ON_REQ: Pin ## = Pin(PMIC_ON_REQ) + GPIO_SD_B1_11: Pin ## = Pin(GPIO_SD_B1_11) + PMIC_STBY_REQ: Pin ## = Pin(PMIC_STBY_REQ) + GPIO_SD_B1_07: Pin ## = Pin(GPIO_SD_B1_07) + GPIO_SD_B1_08: Pin ## = Pin(GPIO_SD_B1_08) + GPIO_SD_B1_10: Pin ## = Pin(GPIO_SD_B1_10) + GPIO_SD_B1_09: Pin ## = Pin(GPIO_SD_B1_09) + GPIO_EMC_31: Pin ## = Pin(GPIO_EMC_31) + GPIO_EMC_30: Pin ## = Pin(GPIO_EMC_30) + GPIO_EMC_32: Pin ## = Pin(GPIO_EMC_32) + GPIO_EMC_33: Pin ## = Pin(GPIO_EMC_33) + GPIO_EMC_27: Pin ## = Pin(GPIO_EMC_27) + GPIO_EMC_29: Pin ## = Pin(GPIO_EMC_29) + GPIO_EMC_28: Pin ## = Pin(GPIO_EMC_28) + GPIO_EMC_41: Pin ## = Pin(GPIO_EMC_41) + GPIO_EMC_39: Pin ## = Pin(GPIO_EMC_39) + GPIO_EMC_38: Pin ## = Pin(GPIO_EMC_38) + GPIO_EMC_40: Pin ## = Pin(GPIO_EMC_40) + GPIO_EMC_34: Pin ## = Pin(GPIO_EMC_34) + GPIO_EMC_35: Pin ## = Pin(GPIO_EMC_35) + GPIO_EMC_37: Pin ## = Pin(GPIO_EMC_37) + GPIO_EMC_36: Pin ## = Pin(GPIO_EMC_36) + GPIO_AD_B1_03: Pin ## = Pin(GPIO_AD_B1_03) + GPIO_AD_B1_02: Pin ## = Pin(GPIO_AD_B1_02) + GPIO_AD_B1_04: Pin ## = Pin(GPIO_AD_B1_04) + GPIO_AD_B1_05: Pin ## = Pin(GPIO_AD_B1_05) + GPIO_AD_B0_15: Pin ## = Pin(GPIO_AD_B0_15) + GPIO_AD_B1_01: Pin ## = Pin(GPIO_AD_B1_01) + GPIO_AD_B1_00: Pin ## = Pin(GPIO_AD_B1_00) + GPIO_B1_11: Pin ## = Pin(GPIO_B1_11) + GPIO_AD_B1_11: Pin ## = Pin(GPIO_AD_B1_11) + GPIO_AD_B1_10: Pin ## = Pin(GPIO_AD_B1_10) + GPIO_AD_B1_12: Pin ## = Pin(GPIO_AD_B1_12) + GPIO_AD_B1_06: Pin ## = Pin(GPIO_AD_B1_06) + GPIO_AD_B1_07: Pin ## = Pin(GPIO_AD_B1_07) + GPIO_AD_B1_09: Pin ## = Pin(GPIO_AD_B1_09) + GPIO_AD_B1_08: Pin ## = Pin(GPIO_AD_B1_08) + GPIO_AD_B0_04: Pin ## = Pin(GPIO_AD_B0_04) + GPIO_AD_B0_03: Pin ## = Pin(GPIO_AD_B0_03) + GPIO_AD_B0_05: Pin ## = Pin(GPIO_AD_B0_05) + GPIO_AD_B0_06: Pin ## = Pin(GPIO_AD_B0_06) + GPIO_AD_B0_00: Pin ## = Pin(GPIO_AD_B0_00) + GPIO_AD_B0_02: Pin ## = Pin(GPIO_AD_B0_02) + GPIO_AD_B0_01: Pin ## = Pin(GPIO_AD_B0_01) + GPIO_AD_B0_14: Pin ## = Pin(GPIO_AD_B0_14) + GPIO_AD_B0_12: Pin ## = Pin(GPIO_AD_B0_12) + GPIO_AD_B0_11: Pin ## = Pin(GPIO_AD_B0_11) + GPIO_AD_B0_13: Pin ## = Pin(GPIO_AD_B0_13) + GPIO_AD_B0_07: Pin ## = Pin(GPIO_AD_B0_07) + GPIO_AD_B0_08: Pin ## = Pin(GPIO_AD_B0_08) + GPIO_AD_B0_10: Pin ## = Pin(GPIO_AD_B0_10) + GPIO_AD_B0_09: Pin ## = Pin(GPIO_AD_B0_09) + GPIO_B1_01: Pin ## = Pin(GPIO_B1_01) + GPIO_B1_00: Pin ## = Pin(GPIO_B1_00) + GPIO_B1_02: Pin ## = Pin(GPIO_B1_02) + GPIO_B1_03: Pin ## = Pin(GPIO_B1_03) + GPIO_B0_13: Pin ## = Pin(GPIO_B0_13) + GPIO_B0_15: Pin ## = Pin(GPIO_B0_15) + GPIO_B0_14: Pin ## = Pin(GPIO_B0_14) + GPIO_AD_B1_13: Pin ## = Pin(GPIO_AD_B1_13) + GPIO_B1_09: Pin ## = Pin(GPIO_B1_09) + GPIO_B1_08: Pin ## = Pin(GPIO_B1_08) + GPIO_B1_10: Pin ## = Pin(GPIO_B1_10) + GPIO_B1_04: Pin ## = Pin(GPIO_B1_04) + GPIO_B1_05: Pin ## = Pin(GPIO_B1_05) + GPIO_B1_07: Pin ## = Pin(GPIO_B1_07) + GPIO_B1_06: Pin ## = Pin(GPIO_B1_06) + GPIO_B0_02: Pin ## = Pin(GPIO_B0_02) + GPIO_B0_01: Pin ## = Pin(GPIO_B0_01) + GPIO_B0_03: Pin ## = Pin(GPIO_B0_03) + GPIO_B0_04: Pin ## = Pin(GPIO_B0_04) + GPIO_AD_B1_14: Pin ## = Pin(GPIO_AD_B1_14) + GPIO_B0_00: Pin ## = Pin(GPIO_B0_00) + GPIO_AD_B1_15: Pin ## = Pin(GPIO_AD_B1_15) + GPIO_B0_12: Pin ## = Pin(GPIO_B0_12) + GPIO_B0_10: Pin ## = Pin(GPIO_B0_10) + GPIO_B0_09: Pin ## = Pin(GPIO_B0_09) + GPIO_B0_11: Pin ## = Pin(GPIO_B0_11) + GPIO_B0_05: Pin ## = Pin(GPIO_B0_05) + GPIO_B0_06: Pin ## = Pin(GPIO_B0_06) + GPIO_B0_08: Pin ## = Pin(GPIO_B0_08) + GPIO_B0_07: Pin ## = Pin(GPIO_B0_07) + def __init__(self, *argv, **kwargs) -> None: ... + + class board: + J5_22: Pin ## = Pin(GPIO_B0_15) + J5_25: Pin ## = Pin(GPIO_B1_02) + J5_24: Pin ## = Pin(GPIO_B1_01) + J5_23: Pin ## = Pin(GPIO_B1_00) + J5_26: Pin ## = Pin(GPIO_B1_03) + J5_30: Pin ## = Pin(GPIO_B0_03) + J5_29: Pin ## = Pin(GPIO_B0_02) + J5_28: Pin ## = Pin(GPIO_B0_01) + J5_06: Pin ## = Pin(GPIO_B0_06) + J5_17: Pin ## = Pin(GPIO_B0_14) + J5_12: Pin ## = Pin(GPIO_B0_09) + J5_08: Pin ## = Pin(GPIO_B0_08) + J5_07: Pin ## = Pin(GPIO_B0_07) + J5_13: Pin ## = Pin(GPIO_B0_10) + J5_16: Pin ## = Pin(GPIO_B0_13) + J5_15: Pin ## = Pin(GPIO_B0_12) + J5_14: Pin ## = Pin(GPIO_B0_11) + LED_GREEN: Pin ## = Pin(GPIO_AD_B0_10) + SCK_RX: Pin ## = Pin(GPIO_AD_B1_11) + MCK: Pin ## = Pin(GPIO_AD_B1_09) + LED_RED: Pin ## = Pin(GPIO_AD_B0_09) + SCK_TX: Pin ## = Pin(GPIO_AD_B1_14) + WS_RX: Pin ## = Pin(GPIO_AD_B1_10) + SD_TX: Pin ## = Pin(GPIO_AD_B1_13) + SD_RX: Pin ## = Pin(GPIO_AD_B1_12) + J5_32: Pin ## = Pin(GPIO_B0_00) + LED_BLUE: Pin ## = Pin(GPIO_AD_B0_11) + J5_36: Pin ## = Pin(GPIO_AD_B1_13) + J5_35: Pin ## = Pin(GPIO_AD_B1_14) + J5_34: Pin ## = Pin(GPIO_AD_B1_15) + J5_37: Pin ## = Pin(GPIO_AD_B1_12) + J5_50: Pin ## = Pin(GPIO_AD_B0_02) + J5_43: Pin ## = Pin(GPIO_AD_B1_01) + J5_42: Pin ## = Pin(GPIO_AD_B1_00) + WS_TX: Pin ## = Pin(GPIO_AD_B1_15) + J3_12: Pin ## = Pin(GPIO_B1_09) + J3_15: Pin ## = Pin(GPIO_AD_B0_15) + J3_14: Pin ## = Pin(GPIO_AD_B0_14) + J3_13: Pin ## = Pin(GPIO_B1_10) + J3_16: Pin ## = Pin(GPIO_AD_B1_00) + J3_20: Pin ## = Pin(GPIO_AD_B0_12) + J3_19: Pin ## = Pin(GPIO_AD_B0_13) + J3_17: Pin ## = Pin(GPIO_AD_B1_01) + J5_05: Pin ## = Pin(GPIO_B0_05) + J3_11: Pin ## = Pin(GPIO_B1_07) + J3_06: Pin ## = Pin(GPIO_EMC_41) + J3_05: Pin ## = Pin(GPIO_B1_06) + J3_04: Pin ## = Pin(GPIO_B1_11) + J3_07: Pin ## = Pin(GPIO_EMC_40) + J3_10: Pin ## = Pin(GPIO_B1_08) + J3_09: Pin ## = Pin(GPIO_B1_04) + J3_08: Pin ## = Pin(GPIO_B1_05) + J4_13: Pin ## = Pin(GPIO_AD_B1_13) + J4_16: Pin ## = Pin(GPIO_AD_B1_02) + J4_15: Pin ## = Pin(GPIO_AD_B1_15) + J4_14: Pin ## = Pin(GPIO_AD_B1_14) + J4_17: Pin ## = Pin(GPIO_AD_B1_03) + J5_04: Pin ## = Pin(GPIO_B0_04) + J4_20: Pin ## = Pin(GPIO_AD_B0_06) + J4_19: Pin ## = Pin(GPIO_AD_B0_07) + J4_04: Pin ## = Pin(GPIO_AD_B1_04) + J4_12: Pin ## = Pin(GPIO_AD_B1_12) + J4_07: Pin ## = Pin(GPIO_AD_B1_07) + J4_06: Pin ## = Pin(GPIO_AD_B1_06) + J4_05: Pin ## = Pin(GPIO_AD_B1_05) + J4_08: Pin ## = Pin(GPIO_AD_B1_08) + J4_11: Pin ## = Pin(GPIO_AD_B1_11) + J4_10: Pin ## = Pin(GPIO_AD_B1_10) + J4_09: Pin ## = Pin(GPIO_AD_B1_09) + def __init__(self, *argv, **kwargs) -> None: ... + + def __init__( + self, + id: Any, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Access the pin peripheral (GPIO pin) associated with the given ``id``. If + additional arguments are given in the constructor then they are used to initialise + the pin. Any settings that are not specified will remain in their previous state. + + The arguments are: + + - ``id`` is mandatory and can be an arbitrary object. Among possible value + types are: int (an internal Pin identifier), str (a Pin name), and tuple + (pair of [port, pin]). + + - ``mode`` specifies the pin mode, which can be one of: + + - ``Pin.IN`` - Pin is configured for input. If viewed as an output the pin + is in high-impedance state. + + - ``Pin.OUT`` - Pin is configured for (normal) output. + + - ``Pin.OPEN_DRAIN`` - Pin is configured for open-drain output. Open-drain + output works in the following way: if the output value is set to 0 the pin + is active at a low level; if the output value is 1 the pin is in a high-impedance + state. Not all ports implement this mode, or some might only on certain pins. + + - ``Pin.ALT`` - Pin is configured to perform an alternative function, which is + port specific. For a pin configured in such a way any other Pin methods + (except :meth:`Pin.init`) are not applicable (calling them will lead to undefined, + or a hardware-specific, result). Not all ports implement this mode. + + - ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as + open-drain. Not all ports implement this mode. + + - ``Pin.ANALOG`` - Pin is configured for analog input, see the :class:`ADC` class. + + - ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be + one of: + + - ``None`` - No pull up or down resistor. + - ``Pin.PULL_UP`` - Pull up resistor enabled. + - ``Pin.PULL_DOWN`` - Pull down resistor enabled. + + - ``value`` is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and specifies initial + output pin value if given, otherwise the state of the pin peripheral remains + unchanged. + + - ``drive`` specifies the output power of the pin and can be one of: ``Pin.LOW_POWER``, + ``Pin.MED_POWER`` or ``Pin.HIGH_POWER``. The actual current driving capabilities + are port dependent. Not all ports implement this argument. + + - ``alt`` specifies an alternate function for the pin and the values it can take are + port dependent. This argument is valid only for ``Pin.ALT`` and ``Pin.ALT_OPEN_DRAIN`` + modes. It may be used when a pin supports more than one alternate function. If only + one pin alternate function is supported the this argument is not required. Not all + ports implement this argument. + + As specified above, the Pin class allows to set an alternate function for a particular + pin, but it does not specify any further operations on such a pin. Pins configured in + alternate-function mode are usually not used as GPIO but are instead driven by other + hardware peripherals. The only operation supported on such a pin is re-initialising, + by calling the constructor or :meth:`Pin.init` method. If a pin that is configured in + alternate-function mode is re-initialised with ``Pin.IN``, ``Pin.OUT``, or + ``Pin.OPEN_DRAIN``, the alternate function will be removed from the pin. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class Signal(Pin): + """ + The Signal class is a simple extension of the `Pin` class. Unlike Pin, which + can be only in "absolute" 0 and 1 states, a Signal can be in "asserted" + (on) or "deasserted" (off) states, while being inverted (active-low) or + not. In other words, it adds logical inversion support to Pin functionality. + While this may seem a simple addition, it is exactly what is needed to + support wide array of simple digital devices in a way portable across + different boards, which is one of the major MicroPython goals. Regardless + of whether different users have an active-high or active-low LED, a normally + open or normally closed relay - you can develop a single, nicely looking + application which works with each of them, and capture hardware + configuration differences in few lines in the config file of your app. + + Example:: + + from machine import Pin, Signal + + # Suppose you have an active-high LED on pin 0 + led1_pin = Pin(0, Pin.OUT) + # ... and active-low LED on pin 1 + led2_pin = Pin(1, Pin.OUT) + + # Now to light up both of them using Pin class, you'll need to set + # them to different values + led1_pin.value(1) + led2_pin.value(0) + + # Signal class allows to abstract away active-high/active-low + # difference + led1 = Signal(led1_pin, invert=False) + led2 = Signal(led2_pin, invert=True) + + # Now lighting up them looks the same + led1.value(1) + led2.value(1) + + # Even better: + led1.on() + led2.on() + + Following is the guide when Signal vs Pin should be used: + + * Use Signal: If you want to control a simple on/off (including software + PWM!) devices like LEDs, multi-segment indicators, relays, buzzers, or + read simple binary sensors, like normally open or normally closed buttons, + pulled high or low, Reed switches, moisture/flame detectors, etc. etc. + Summing up, if you have a real physical device/sensor requiring GPIO + access, you likely should use a Signal. + + * Use Pin: If you implement a higher-level protocol or bus to communicate + with more complex devices. + + The split between Pin and Signal come from the use cases above and the + architecture of MicroPython: Pin offers the lowest overhead, which may + be important when bit-banging protocols. But Signal adds additional + flexibility on top of Pin, at the cost of minor overhead (much smaller + than if you implemented active-high vs active-low device differences in + Python manually!). Also, Pin is a low-level object which needs to be + implemented for each support board, while Signal is a high-level object + which comes for free once Pin is implemented. + + If in doubt, give the Signal a try! Once again, it is offered to save + developers from the need to handle unexciting differences like active-low + vs active-high signals, and allow other users to share and enjoy your + application, instead of being frustrated by the fact that it doesn't + work for them simply because their LEDs or relays are wired in a slightly + different way. + """ + def off(self) -> None: + """ + Deactivate signal. + """ + ... + def on(self) -> None: + """ + Activate signal. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + +class RTC: + """ + The RTC is an independent clock that keeps track of the date + and time. + + Example usage:: + + rtc = machine.RTC() + rtc.datetime((2020, 1, 21, 2, 10, 32, 36, 0)) + print(rtc.datetime()) + + + + The documentation for RTC is in a poor state;1 + """ + + ALARM0: Final[int] = 0 + """irq trigger source""" + def irq( + self, + /, + *, + trigger: int, + handler: Callable[[RTC], None] | None = None, + wake: int = IDLE, + ) -> None: + """ + Create an irq object triggered by a real time clock alarm. + + - ``trigger`` must be ``RTC.ALARM0`` + - ``handler`` is the function to be called when the callback is triggered. + - ``wake`` specifies the sleep mode from where this interrupt can wake + up the system. + """ + ... + def cancel(self, *args, **kwargs) -> Incomplete: ... + def datetime(self, datetimetuple: Any | None = None) -> Tuple: + """ + Get or set the date and time of the RTC. + + With no arguments, this method returns an 8-tuple with the current + date and time. With 1 argument (being an 8-tuple) it sets the date + and time. + + The 8-tuple has the following format: + + (year, month, day, weekday, hours, minutes, seconds, subseconds) + + The meaning of the ``subseconds`` field is hardware dependent. + """ + ... + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + def calibration(self, *args, **kwargs) -> Incomplete: ... + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + def alarm_cancel(self, alarm_id: int = 0, /) -> None: + """ + Cancel a running alarm. + + The mimxrt port also exposes this function as ``RTC.cancel(alarm_id=0)``, but this is + scheduled to be removed in MicroPython 2.0. + """ + ... + def alarm_left(self, alarm_id: int = 0, /) -> int: + """ + Get the number of milliseconds left before the alarm expires. + """ + ... + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + +class SDCard(AbstractBlockDev): + """ + SD cards are one of the most common small form factor removable storage media. + SD cards come in a variety of sizes and physical form factors. MMC cards are + similar removable storage devices while eMMC devices are electrically similar + storage devices designed to be embedded into other systems. All three form + share a common protocol for communication with their host system and high-level + support looks the same for them all. As such in MicroPython they are implemented + in a single class called :class:`machine.SDCard` . + + Both SD and MMC interfaces support being accessed with a variety of bus widths. + When being accessed with a 1-bit wide interface they can be accessed using the + SPI protocol. Different MicroPython hardware platforms support different widths + and pin configurations but for most platforms there is a standard configuration + for any given hardware. In general constructing an ``SDCard`` object with without + passing any parameters will initialise the interface to the default card slot + for the current hardware. The arguments listed below represent the common + arguments that might need to be set in order to use either a non-standard slot + or a non-standard pin assignment. The exact subset of arguments supported will + vary from platform to platform. + + + Implementation-specific details + ------------------------------- + + Different implementations of the ``SDCard`` class on different hardware support + varying subsets of the options above. + + PyBoard + ``````` + + The standard PyBoard has just one slot. No arguments are necessary or supported. + + ESP32 + ````` + + The ESP32 provides two channels of SD/MMC hardware and also supports + access to SD Cards through either of the two SPI ports that are + generally available to the user. As a result the *slot* argument can + take a value between 0 and 3, inclusive. Slots 0 and 1 use the + built-in SD/MMC hardware while slots 2 and 3 use the SPI ports. Slot 0 + supports 1, 4 or 8-bit wide access while slot 1 supports 1 or 4-bit + access; the SPI slots only support 1-bit access. + + .. note:: Slot 0 is used to communicate with on-board flash memory + on most ESP32 modules and so will be unavailable to the + user. + + .. note:: Most ESP32 modules that provide an SD card slot using the + dedicated hardware only wire up 1 data pin, so the default + value for *width* is 1. + + The pins used by the dedicated SD/MMC hardware are fixed. The pins + used by the SPI hardware can be reassigned. + + .. note:: If any of the SPI signals are remapped then all of the SPI + signals will pass through a GPIO multiplexer unit which + can limit the performance of high frequency signals. Since + the normal operating speed for SD cards is 40MHz this can + cause problems on some cards. + + The default (and preferred) pin assignment are as follows: + + ====== ====== ====== ====== ====== + Slot 0 1 2 3 + ------ ------ ------ ------ ------ + Signal Pin Pin Pin Pin + ====== ====== ====== ====== ====== + sck 6 14 18 14 + cmd 11 15 + cs 5 15 + miso 19 12 + mosi 23 13 + D0 7 2 + D1 8 4 + D2 9 12 + D3 10 13 + D4 16 + D5 17 + D6 5 + D7 18 + ====== ====== ====== ====== ====== + + cc3200 + `````` + + You can set the pins used for SPI access by passing a tuple as the + *pins* argument. + + *Note:* The current cc3200 SD card implementation names the this class + :class:`machine.SD` rather than :class:`machine.SDCard` . + """ + def present(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def info(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SPI: + """ + SPI is a synchronous serial protocol that is driven by a controller. At the + physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices + can share the same bus. Each device should have a separate, 4th signal, + CS (Chip Select), to select a particular device on a bus with which + communication takes place. Management of a CS signal should happen in + user code (via machine.Pin class). + + Both hardware and software SPI implementations exist via the + :ref:`machine.SPI ` and `machine.SoftSPI` classes. Hardware SPI uses underlying + hardware support of the system to perform the reads/writes and is usually + efficient and fast but may have restrictions on which pins can be used. + Software SPI is implemented by bit-banging and can be used on any pin but + is not as efficient. These classes have the same methods available and + differ primarily in the way they are constructed. + + Example usage:: + + from machine import SPI, Pin + + spi = SPI(0, baudrate=400000) # Create SPI peripheral 0 at frequency of 400kHz. + # Depending on the use case, extra parameters may be required + # to select the bus characteristics and/or pins to use. + cs = Pin(4, mode=Pin.OUT, value=1) # Create chip-select on pin 4. + + try: + cs(0) # Select peripheral. + spi.write(b"12345678") # Write 8 bytes, and don't care about received data. + finally: + cs(1) # Deselect peripheral. + + try: + cs(0) # Select peripheral. + rxdata = spi.read(8, 0x42) # Read 8 bytes while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + rxdata = bytearray(8) + try: + cs(0) # Select peripheral. + spi.readinto(rxdata, 0x42) # Read 8 bytes inplace while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + txdata = b"12345678" + rxdata = bytearray(len(txdata)) + try: + cs(0) # Select peripheral. + spi.write_readinto(txdata, rxdata) # Simultaneously write and read bytes. + finally: + cs(1) # Deselect peripheral. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + CONTROLLER: Incomplete + def deinit(self) -> None: + """ + Turn off the SPI bus. + """ + ... + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + def write_readinto(self, write_buf: AnyReadableBuf, read_buf: AnyWritableBuf, /) -> int: + """ + Write the bytes from ``write_buf`` while reading into ``read_buf``. The + buffers can be the same or different, but both buffers must have the + same length. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def read(self, nbytes: int, write: int = 0x00, /) -> bytes: + """ + Read a number of bytes specified by ``nbytes`` while continuously writing + the single byte given by ``write``. + Returns a ``bytes`` object with the data that was read. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes contained in ``buf``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def readinto(self, buf: AnyWritableBuf, write: int = 0x00, /) -> int: + """ + Read into the buffer specified by ``buf`` while continuously writing the + single byte given by ``write``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes read. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/math.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/math.pyi new file mode 100644 index 000000000..dcc5cea90 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/math.pyi @@ -0,0 +1,269 @@ +""" +Mathematical functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/math.html + +CPython module: :mod:`python:math` https://docs.python.org/3/library/math.html . + +The ``math`` module provides some basic mathematical functions for +working with floating-point numbers. + +*Note:* On the pyboard, floating-point numbers have 32-bit precision. + +Availability: not available on WiPy. Floating point support required +for this module. + +--- +Module: 'math' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsFloat, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +inf: float = inf +nan: float = nan +pi: float = 3.141592653589793 +"""the ratio of a circle's circumference to its diameter""" +e: float = 2.718281828459045 +"""base of the natural logarithm""" +tau: float = 6.283185307179586 + +def ldexp(x: SupportsFloat, exp: int, /) -> float: + """ + Return ``x * (2**exp)``. + """ + ... + +def lgamma(x: SupportsFloat, /) -> float: + """ + Return the natural logarithm of the gamma function of ``x``. + """ + ... + +def trunc(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards 0. + """ + ... + +def isclose(*args, **kwargs) -> Incomplete: ... +def gamma(x: SupportsFloat, /) -> float: + """ + Return the gamma function of ``x``. + """ + ... + +def isnan(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is not-a-number + """ + ... + +def isfinite(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is finite. + """ + ... + +def isinf(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is infinite. + """ + ... + +def sqrt(x: SupportsFloat, /) -> float: + """ + Return the square root of ``x``. + """ + ... + +def sinh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic sine of ``x``. + """ + ... + +def log(x: SupportsFloat, /) -> float: + """ + With one argument, return the natural logarithm of *x*. + + With two arguments, return the logarithm of *x* to the given *base*. + """ + ... + +def tan(x: SupportsFloat, /) -> float: + """ + Return the tangent of ``x``. + """ + ... + +def tanh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic tangent of ``x``. + """ + ... + +def log2(x: SupportsFloat, /) -> float: + """ + Return the base-2 logarithm of ``x``. + """ + ... + +def log10(x: SupportsFloat, /) -> float: + """ + Return the base-10 logarithm of ``x``. + """ + ... + +def sin(x: SupportsFloat, /) -> float: + """ + Return the sine of ``x``. + """ + ... + +def modf(x: SupportsFloat, /) -> Tuple: + """ + Return a tuple of two floats, being the fractional and integral parts of + ``x``. Both return values have the same sign as ``x``. + """ + ... + +def radians(x: SupportsFloat, /) -> float: + """ + Return degrees ``x`` converted to radians. + """ + ... + +def atanh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic tangent of ``x``. + """ + ... + +def atan2(y: SupportsFloat, x: SupportsFloat, /) -> float: + """ + Return the principal value of the inverse tangent of ``y/x``. + """ + ... + +def atan(x: SupportsFloat, /) -> float: + """ + Return the inverse tangent of ``x``. + """ + ... + +def ceil(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards positive infinity. + """ + ... + +def copysign(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return ``x`` with the sign of ``y``. + """ + ... + +def frexp(x: SupportsFloat, /) -> tuple[float, 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 acos(x: SupportsFloat, /) -> float: + """ + Return the inverse cosine of ``x``. + """ + ... + +def pow(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Returns ``x`` to the power of ``y``. + """ + ... + +def asinh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic sine of ``x``. + """ + ... + +def acosh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic cosine of ``x``. + """ + ... + +def asin(x: SupportsFloat, /) -> float: + """ + Return the inverse sine of ``x``. + """ + ... + +def factorial(*args, **kwargs) -> Incomplete: ... +def fabs(x: SupportsFloat, /) -> float: + """ + Return the absolute value of ``x``. + """ + ... + +def expm1(x: SupportsFloat, /) -> float: + """ + Return ``exp(x) - 1``. + """ + ... + +def floor(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards negative infinity. + """ + ... + +def fmod(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return the remainder of ``x/y``. + """ + ... + +def cos(x: SupportsFloat, /) -> float: + """ + Return the cosine of ``x``. + """ + ... + +def degrees(x: SupportsFloat, /) -> float: + """ + Return radians ``x`` converted to degrees. + """ + ... + +def cosh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic cosine of ``x``. + """ + ... + +def exp(x: SupportsFloat, /) -> float: + """ + Return the exponential of ``x``. + """ + ... + +def erf(x: SupportsFloat, /) -> float: + """ + Return the error function of ``x``. + """ + ... + +def erfc(x: SupportsFloat, /) -> float: + """ + Return the complementary error function of ``x``. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/micropython.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/micropython.pyi new file mode 100644 index 000000000..42982aee2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/micropython.pyi @@ -0,0 +1,346 @@ +""" +Access and control MicroPython internals. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/micropython.html + +--- +Module: 'micropython' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Any, Callable, Optional, Tuple, overload +from typing_extensions import Awaitable, ParamSpec, TypeAlias, TypeVar + +_T = TypeVar("_T") +_F = TypeVar("_F", bound=Callable[..., Any]) +Const_T = TypeVar("Const_T", int, float, str, bytes, Tuple) +_Param = ParamSpec("_Param") +_Ret = TypeVar("_Ret") + +@overload +def opt_level() -> int: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def opt_level(level: int, /) -> None: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def mem_info() -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +@overload +def mem_info(verbose: Any, /) -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +def kbd_intr(chr: int) -> None: + """ + Set the character that will raise a `KeyboardInterrupt` exception. By + default this is set to 3 during script execution, corresponding to Ctrl-C. + Passing -1 to this function will disable capture of Ctrl-C, and passing 3 + will restore it. + + This function can be used to prevent the capturing of Ctrl-C on the + incoming stream of characters that is usually used for the REPL, in case + that stream is used for other purposes. + """ + ... + +@overload +def qstr_info() -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +@overload +def qstr_info(verbose: bool, /) -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +def schedule(func: Callable[[_T], None], arg: _T, /) -> None: + """ + Schedule the function *func* to be executed "very soon". The function + is passed the value *arg* as its single argument. "Very soon" means that + the MicroPython runtime will do its best to execute the function at the + earliest possible time, given that it is also trying to be efficient, and + that the following conditions hold: + + - A scheduled function will never preempt another scheduled function. + - Scheduled functions are always executed "between opcodes" which means + that all fundamental Python operations (such as appending to a list) + are guaranteed to be atomic. + - A given port may define "critical regions" within which scheduled + functions will never be executed. Functions may be scheduled within + a critical region but they will not be executed until that region + is exited. An example of a critical region is a preempting interrupt + handler (an IRQ). + + A use for this function is to schedule a callback from a preempting IRQ. + Such an IRQ puts restrictions on the code that runs in the IRQ (for example + the heap may be locked) and scheduling a function to call later will lift + those restrictions. + + On multi-threaded ports, the scheduled function's behaviour depends on + whether the Global Interpreter Lock (GIL) is enabled for the specific port: + + - If GIL is enabled, the function can preempt any thread and run in its + context. + - If GIL is disabled, the function will only preempt the main thread and run + in its context. + + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite queue to hold the scheduled functions and `schedule()` + will raise a `RuntimeError` if the queue is full. + """ + ... + +def stack_use() -> int: + """ + Return an integer representing the current amount of stack that is being + used. The absolute value of this is not particularly useful, rather it + should be used to compute differences in stack usage at different points. + """ + ... + +def heap_unlock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def const(expr: Const_T, /) -> Const_T: + """ + Used to declare that the expression is a constant so that the compiler can + optimise it. The use of this function should be as follows:: + + from micropython import const + + CONST_X = const(123) + CONST_Y = const(2 * CONST_X + 1) + + Constants declared this way are still accessible as global variables from + outside the module they are declared in. On the other hand, if a constant + begins with an underscore then it is hidden, it is not available as a global + variable, and does not take up any memory during execution. + + This `const` function is recognised directly by the MicroPython parser and is + provided as part of the :mod:`micropython` module mainly so that scripts can be + written which run under both CPython and MicroPython, by following the above + pattern. + """ + ... + +def heap_lock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def alloc_emergency_exception_buf(size: int, /) -> None: + """ + Allocate *size* bytes of RAM for the emergency exception buffer (a good + size is around 100 bytes). The buffer is used to create exceptions in cases + when normal RAM allocation would fail (eg within an interrupt handler) and + therefore give useful traceback information in these situations. + + A good way to use this function is to put it at the start of your main script + (eg ``boot.py`` or ``main.py``) and then the emergency exception buffer will be active + for all the code following it. + """ + ... + +class RingIO: + def readinto(self, buf, nbytes: Optional[Any] = None) -> int: + """ + Read available bytes into the provided ``buf``. If ``nbytes`` is + specified then read at most that many bytes. Otherwise, read at + most ``len(buf)`` bytes. + + Return value: Integer count of the number of bytes read into ``buf``. + """ + ... + def write(self, buf) -> int: + """ + Non-blocking write of bytes from ``buf`` into the ringbuffer, limited + by the available space in the ringbuffer. + + Return value: Integer count of bytes written. + """ + ... + def readline(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read a line, ending in a newline character or return if one exists in + the buffer, else return available bytes in buffer. If ``nbytes`` is + specified then read at most that many bytes. + + Return value: a bytes object containing the line read. + """ + ... + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read. + """ + ... + def read(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read available characters. This is a non-blocking function. If ``nbytes`` + is specified then read at most that many bytes, otherwise read as much + data as possible. + + Return value: a bytes object containing the bytes read. Will be + zero-length bytes object if no data is available. + """ + ... + def close(self) -> Incomplete: + """ + No-op provided as part of standard `stream` interface. Has no effect + on data in the ringbuffer. + """ + ... + def __init__(self, size) -> None: ... + +# decorators +@mp_available() # force merge +def viper(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + The Viper code emitter is not fully compliant. It supports special Viper native data types in pursuit of performance. + Integer processing is non-compliant because it uses machine words: arithmetic on 32 bit hardware is performed modulo 2**32. + Like the Native emitter Viper produces machine instructions but further optimisations are performed, substantially increasing + performance especially for integer arithmetic and bit manipulations. + See: https://docs.micropython.org/en/latest/reference/speed_python.html?highlight=viper#the-native-code-emitter + """ + ... + +@mp_available() # force merge +def native(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This causes the MicroPython compiler to emit native CPU opcodes rather than bytecode. + It covers the bulk of the MicroPython functionality, so most functions will require no adaptation. + See: https://docs.micropython.org/en/latest/reference/speed_python.html#the-native-code-emitter + """ + ... + +@mp_available(macro="MICROPY_EMIT_INLINE_THUMB") # force merge +def asm_thumb(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code. + The assembler code is written is a subset of the ARM Thumb-2 instruction set, and is executed on the target CPU. + + Availability: Only on specific boards where MICROPY_EMIT_INLINE_THUMB is defined. + See: https://docs.micropython.org/en/latest/reference/asm_thumb2_index.html + """ + ... + +@mp_available(port="esp8266") # force merge +def asm_xtensa(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code for the esp8266. + The assembler code is written in the Xtensa instruction set, and is executed on the target CPU. + + Availability: Only on eps8266 boards. + """ + ... + # See : + # - https://github.com/orgs/micropython/discussions/12965 + # - https://github.com/micropython/micropython/pull/16731 diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mimxrt.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mimxrt.pyi new file mode 100644 index 000000000..8ecccefdf --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mimxrt.pyi @@ -0,0 +1,14 @@ +""" +Module: 'mimxrt' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class Flash: + def readblocks(self, *args, **kwargs) -> Incomplete: ... + def writeblocks(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mip/__init__.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mip/__init__.pyi new file mode 100644 index 000000000..466c68177 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mip/__init__.pyi @@ -0,0 +1,38 @@ +""" +Module: 'mip.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +allowed_mip_url_prefixes: tuple = () +_CHUNK_SIZE: Final[int] = 128 +def _ensure_path_exists(*args, **kwargs) -> Incomplete: + ... + +def _install_json(*args, **kwargs) -> Incomplete: + ... + +def _install_package(*args, **kwargs) -> Incomplete: + ... + +def _rewrite_url(*args, **kwargs) -> Incomplete: + ... + +def install(*args, **kwargs) -> Incomplete: + ... + +def _download_file(*args, **kwargs) -> Incomplete: + ... + +def const(*args, **kwargs) -> Incomplete: + ... + +def _check_exists(*args, **kwargs) -> Incomplete: + ... + +def _chunk(*args, **kwargs) -> Incomplete: + ... + diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/network.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/network.pyi new file mode 100644 index 000000000..9ffd68e9d --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/network.pyi @@ -0,0 +1,551 @@ +""" +Network configuration. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/network.html + +This module provides network drivers and routing configuration. To use this +module, a MicroPython variant/build with network capabilities must be installed. +Network drivers for specific hardware are available within this module and are +used to configure hardware network interface(s). Network services provided +by configured interfaces are then available for use via the :mod:`socket` +module. + +For example:: + + # connect/ show IP config a specific network interface + # see below for examples of specific drivers + import network + import time + nic = network.Driver(...) + if not nic.isconnected(): + nic.connect() + print("Waiting for connection...") + while not nic.isconnected(): + time.sleep(1) + print(nic.ipconfig("addr4")) + + # now use socket as usual + import socket + addr = socket.getaddrinfo('micropython.org', 80)[0][-1] + s = socket.socket() + s.connect(addr) + s.send(b'GET / HTTP/1.1 +Host: micropython.org + +') + data = s.recv(1000) + s.close() + +--- +Module: 'network' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Protocol, Callable, overload, Any, List, Optional, Tuple, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar +from machine import Pin, SPI +from abc import abstractmethod + +STA_IF: Final[int] = 0 +AP_IF: Final[int] = 1 + +def route(*args, **kwargs) -> Incomplete: ... +def hostname(name: Optional[Any] = None) -> Incomplete: + """ + Get or set the hostname that will identify this device on the network. It will + be used by all interfaces. + + This hostname is used for: + * Sending to the DHCP server in the client request. (If using DHCP) + * Broadcasting via mDNS. (If enabled) + + If the *name* parameter is provided, the hostname will be set to this value. + If the function is called without parameters, it returns the current + hostname. + + A change in hostname is typically only applied during connection. For DHCP + this is because the hostname is part of the DHCP client request, and the + implementation of mDNS in most ports only initialises the hostname once + during connection. For this reason, you must set the hostname before + activating/connecting your network interfaces. + + The length of the hostname is limited to 32 characters. + :term:`MicroPython ports ` may choose to set a lower + limit for memory reasons. If the given name does not fit, a `ValueError` + is raised. + + The default hostname is typically the name of the board. + """ + ... + +def ipconfig(param: Optional[str] = None, *args, **kwargs) -> str: + """ + Get or set global IP-configuration parameters. + Supported parameters are the following (availability of a particular + parameter depends on the port and the specific network interface): + + * ``dns`` Get/set DNS server. This method can support both, IPv4 and + IPv6 addresses. + * ``prefer`` (``4/6``) Specify which address type to return, if a domain + name has both A and AAAA records. Note, that this does not clear the + local DNS cache, so that any previously obtained addresses might not + change. + """ + ... + +def country(code: Optional[Any] = None) -> Incomplete: + """ + Get or set the two-letter ISO 3166-1 Alpha-2 country code to be used for + radio compliance. + + If the *code* parameter is provided, the country will be set to this value. + If the function is called without parameters, it returns the current + country. + + The default code ``"XX"`` represents the "worldwide" region. + """ + ... + +class PPP: + """ + Create a PPP driver object. + + Arguments are: + + - *stream* is any object that supports the stream protocol, but is most commonly a + :class:`machine.UART` instance. This stream object must have an ``irq()`` method + and an ``IRQ_RXIDLE`` constant, for use by `PPP.connect`. + """ + + SEC_NONE: Final[int] = 0 + """The type of connection security.""" + SEC_PAP: Final[int] = 1 + """The type of connection security.""" + SEC_CHAP: Final[int] = 2 + """The type of connection security.""" + def status(self) -> Incomplete: + """ + Returns the PPP status. + """ + ... + def ipconfig(self, param) -> Incomplete: + """ + See `AbstractNIC.ipconfig`. + """ + ... + def isconnected(self) -> bool: + """ + Returns ``True`` if the PPP link is connected and up. + Returns ``False`` otherwise. + """ + ... + def poll(self) -> Incomplete: + """ + Poll the underlying stream for data, and pass it up the PPP stack. + This is called automatically if the stream is a UART with a RXIDLE interrupt, + so it's not usually necessary to call it manually. + """ + ... + def ifconfig(self, configtuple: Any | None = None) -> Incomplete: + """ + See `AbstractNIC.ifconfig`. + """ + ... + def config(self, config_parameters) -> Incomplete: + """ + Sets or gets parameters of the PPP interface. The only parameter that can be + retrieved and set is the underlying stream, using:: + + stream = PPP.config("stream") + PPP.config(stream=stream) + """ + ... + def connect(self, security=SEC_NONE, user=None, key=None) -> Incomplete: + """ + Initiate a PPP connection with the given parameters: + + - *security* is the type of security, either ``PPP.SEC_NONE``, ``PPP.SEC_PAP``, + or ``PPP.SEC_CHAP``. + - *user* is an optional user name to use with the security mode. + - *key* is an optional password to use with the security mode. + + When this method is called the underlying stream has its interrupt configured to call + `PPP.poll` via ``stream.irq(ppp.poll, stream.IRQ_RXIDLE)``. This makes sure the + stream is polled, and data passed up the PPP stack, wheverver data becomes available + on the stream. + + The connection proceeds asynchronously, in the background. + """ + ... + def disconnect(self) -> Incomplete: + """ + Terminate the connection. This must be called to cleanly close the PPP connection. + """ + ... + def __init__(self, stream) -> None: ... + +class LAN: + """ + Create a LAN driver object, initialise the LAN module using the given + PHY driver name, and return the LAN object. + + Arguments are: + + - *id* is the number of the Ethernet port, either 0 or 1. + - *phy_type* is the name of the PHY driver. For most board the on-board PHY has to be used and + is the default. Suitable values are port specific. + - *phy_addr* specifies the address of the PHY interface. As with *phy_type*, the hardwired value has + to be used for most boards and that value is the default. + - *ref_clk_mode* specifies, whether the data clock is provided by the Ethernet controller or + the PYH interface. + The default value is the one that matches the board. If set to ``LAN.OUT`` or ``Pin.OUT`` + or ``True``, the clock is driven by the Ethernet controller, if set to ``LAN.IN`` + or ``Pin.IN`` or ``False``, the clock is driven by the PHY interface. + + For example, with the Seeed Arch Mix board you can use:: + + nic = LAN(0, phy_type=LAN.PHY_LAN8720, phy_addr=1, ref_clk_mode=Pin.IN) + """ + + PHY_KSZ8081: Final[int] = 0 + PHY_DP83848: Final[int] = 2 + PHY_LAN8720: Final[int] = 3 + PHY_RTL8211F: Final[int] = 4 + IN: Final[int] = 0 + PHY_DP83825: Final[int] = 1 + OUT: Final[int] = 1 + def ipconfig(self, *args, **kwargs) -> Incomplete: ... + def status(self) -> Incomplete: + """ + Returns the LAN status. + """ + ... + def isconnected(self) -> bool: + """ + Returns ``True`` if the physical Ethernet link is connected and up. + Returns ``False`` otherwise. + """ + ... + @overload + def active(self, /) -> bool: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ + + @overload + def active(self, is_active: bool | int, /) -> None: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ + def ifconfig(self, configtuple: Any | None = None) -> Tuple: + """ + Get/set IP address, subnet mask, gateway and DNS. + + When called with no arguments, this method returns a 4-tuple with the above information. + + To set the above values, pass a 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + ... + def config(self, config_parameters) -> Incomplete: + """ + Sets or gets parameters of the LAN interface. The only parameter that can be + retrieved is the MAC address, using:: + + mac = LAN.config("mac") + + The parameters that can be set are: + + - ``trace=n`` sets trace levels; suitable values are: + + - 2: trace TX + - 4: trace RX + - 8: full trace + + - ``low_power=bool`` sets or clears low power mode, valid values being ``False`` + or ``True``. + """ + ... + def __init__(self, id, *, phy_type=0, phy_addr=0, ref_clk_mode=0) -> None: ... + +class WLANWiPy: + @overload + def __init__(self, id: int = 0, /): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int, + ssid: str, + auth: tuple[str, str], + channel: int, + antenna: int, + ): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def mode(self) -> int: + """ + Get or set the WLAN mode. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the WLAN mode. + """ + + @overload + def ssid(self) -> str: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def ssid(self, ssid: str, /) -> None: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def auth(self) -> int: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def auth(self, auth: int, /) -> None: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def channel(self) -> int: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def channel(self, channel: int, /) -> None: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def antenna(self) -> int: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def antenna(self, antenna: int, /) -> None: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def mac(self) -> bytes: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + + @overload + def mac(self, mac: bytes, /) -> None: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + +class AbstractNIC: + @overload + @abstractmethod + def active(self, /) -> bool: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def active(self, is_active: bool | int, /) -> None: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def connect(self, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def connect(self, service_id: Any, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def status(self) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def status(self, param: str, /) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def ifconfig(self) -> tuple[str, str, str, str]: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def ifconfig(self, ip_mask_gateway_dns: tuple[str, str, str, str], /) -> None: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def config(self, param: str, /) -> Any: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ + + @overload + @abstractmethod + def config(self, **kwargs: Any) -> None: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ntptime.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ntptime.pyi new file mode 100644 index 000000000..617a66875 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ntptime.pyi @@ -0,0 +1,15 @@ +""" +Module: 'ntptime' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +timeout: int = 1 +host: str = "pool.ntp.org" + +def time(*args, **kwargs) -> Incomplete: ... +def settime(*args, **kwargs) -> Incomplete: ... +def gmtime(*args, **kwargs) -> Incomplete: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/onewire.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/onewire.pyi new file mode 100644 index 000000000..4994ced18 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/onewire.pyi @@ -0,0 +1,28 @@ +""" +Module: 'onewire' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SKIP_ROM: Final[int] = 204 + SEARCH_ROM: Final[int] = 240 + MATCH_ROM: Final[int] = 85 + def select_rom(self, *args, **kwargs) -> Incomplete: ... + def writebit(self, *args, **kwargs) -> Incomplete: ... + def writebyte(self, *args, **kwargs) -> Incomplete: ... + def _search_rom(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def crc8(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def reset(self, *args, **kwargs) -> Incomplete: ... + def readbit(self, *args, **kwargs) -> Incomplete: ... + def readbyte(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/platform.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/platform.pyi new file mode 100644 index 000000000..a84342847 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/platform.pyi @@ -0,0 +1,51 @@ +""" +Access to underlying platform’s identifying data. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/platform.html + +CPython module: :mod:`python:platform` https://docs.python.org/3/library/platform.html . + +This module tries to retrieve as much platform-identifying data as possible. It +makes this information available via function APIs. + +--- +Module: 'platform' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def platform() -> str: + """ + Returns a string identifying the underlying platform. This string is composed + of several substrings in the following order, delimited by dashes (``-``): + + - the name of the platform system (e.g. Unix, Windows or MicroPython) + - the MicroPython version + - the architecture of the platform + - the version of the underlying platform + - the concatenation of the name of the libc that MicroPython is linked to + and its corresponding version. + + For example, this could be + ``"MicroPython-1.20.0-xtensa-IDFv4.2.4-with-newlib3.0.0"``. + """ + ... + +def python_compiler() -> str: + """ + Returns a string identifying the compiler used for compiling MicroPython. + """ + ... + +def libc_ver() -> Tuple: + """ + Returns a tuple of strings *(lib, version)*, where *lib* is the name of the + libc that MicroPython is linked to, and *version* the corresponding version + of this libc. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/pyproject.toml b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/pyproject.toml new file mode 100644 index 000000000..1b9ac0d2c --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/pyproject.toml @@ -0,0 +1,108 @@ +[project] +name = "micropython-mimxrt-seeed_arch_mix-stubs" +description = "MicroPython stubs" +version = "1.26.1.post1" +readme = "README.md" +license = "MIT" +authors = [ + { name = "Jos Verlinde", email = "josverl@users.noreply.github.com" }, +] +classifiers = [ + "Typing :: Stubs Only", + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Implementation :: MicroPython", + "Operating System :: OS Independent", + "Topic :: Text Editors :: Integrated Development Environments (IDE)", + "Topic :: Software Development :: Documentation", + "Topic :: Software Development :: Embedded Systems", + "Topic :: Software Development :: Testing", + "Natural Language :: English", +] +dependencies = [ + "micropython-stdlib-stubs ~=1.26.0", +] + +[project.urls] +homepage = "https://github.com/josverl/micropython-stubs#micropython-stubs" +documentation = "https://micropython-stubs.readthedocs.io/" +repository = "https://github.com/josverl/micropython-stubs" + +[tool.poetry] +exclude = [ + "*.ps1", + "*.py", + "**/__pycache__", + "**/dist", +] +include = [ + "**/*.py", + "**/*.pyi", +] +packages = [ + { include = "__builtins__.pyi" }, + { include = "_onewire.pyi" }, + { include = "binascii.pyi" }, + { include = "cmath.pyi" }, + { include = "cryptolib.pyi" }, + { include = "deflate.pyi" }, + { include = "dht.pyi" }, + { include = "ds18x20.pyi" }, + { include = "errno.pyi" }, + { include = "framebuf.pyi" }, + { include = "gc.pyi" }, + { include = "hashlib.pyi" }, + { include = "heapq.pyi" }, + { include = "lwip.pyi" }, + { include = "machine.pyi" }, + { include = "math.pyi" }, + { include = "micropython.pyi" }, + { include = "mimxrt.pyi" }, + { include = "mip/__init__.pyi" }, + { include = "network.pyi" }, + { include = "ntptime.pyi" }, + { include = "onewire.pyi" }, + { include = "platform.pyi" }, + { include = "random.pyi" }, + { include = "requests/__init__.pyi" }, + { include = "select.pyi" }, + { include = "socket.pyi" }, + { include = "time.pyi" }, + { include = "tls.pyi" }, + { include = "uarray.pyi" }, + { include = "uasyncio.pyi" }, + { include = "ubinascii.pyi" }, + { include = "ubluetooth.pyi" }, + { include = "ucollections.pyi" }, + { include = "ucryptolib.pyi" }, + { include = "uctypes.pyi" }, + { include = "uerrno.pyi" }, + { include = "uhashlib.pyi" }, + { include = "uheapq.pyi" }, + { include = "uio.pyi" }, + { include = "ujson.pyi" }, + { include = "umachine.pyi" }, + { include = "uos.pyi" }, + { include = "uplatform.pyi" }, + { include = "urandom.pyi" }, + { include = "ure.pyi" }, + { include = "urequests.pyi" }, + { include = "uselect.pyi" }, + { include = "usocket.pyi" }, + { include = "ussl.pyi" }, + { include = "ustruct.pyi" }, + { include = "usys.pyi" }, + { include = "utime.pyi" }, + { include = "uwebsocket.pyi" }, + { include = "uzlib.pyi" }, + { include = "vfs.pyi" }, + { include = "websocket.pyi" }, +] + +[build-system] +requires = [ + "poetry-core>=1.0.0", +] +build-backend = "poetry.core.masonry.api" diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/random.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/random.pyi new file mode 100644 index 000000000..52c922661 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/random.pyi @@ -0,0 +1,115 @@ +""" +Random numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/random.html + +This module implements a pseudo-random number generator (PRNG). + +CPython module: :mod:`python:random` https://docs.python.org/3/library/random.html . . + +.. note:: + + The following notation is used for intervals: + + - () are open interval brackets and do not include their endpoints. + For example, (0, 1) means greater than 0 and less than 1. + In set notation: (0, 1) = {x | 0 < x < 1}. + + - [] are closed interval brackets which include all their limit points. + For example, [0, 1] means greater than or equal to 0 and less than + or equal to 1. + In set notation: [0, 1] = {x | 0 <= x <= 1}. + +.. note:: + + The :func:`randrange`, :func:`randint` and :func:`choice` functions are only + available if the ``MICROPY_PY_RANDOM_EXTRA_FUNCS`` configuration option is + enabled. + +--- +Module: 'random' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import Subscriptable +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +@overload +def randrange(stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, step: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +def random() -> int: + """ + Return a random floating point number in the range [0.0, 1.0). + """ + ... + +def seed(n: int | None = None, /) -> None: + """ + Initialise the random number generator module with the seed *n* which should + be an integer. When no argument (or ``None``) is passed in it will (if + supported by the port) initialise the PRNG with a true random number + (usually a hardware generated random number). + + The ``None`` case only works if ``MICROPY_PY_RANDOM_SEED_INIT_FUNC`` is + enabled by the port, otherwise it raises ``ValueError``. + """ + ... + +def uniform(a: float, b: float) -> int: + """ + Return a random floating point number N such that *a* <= N <= *b* for *a* <= *b*, + and *b* <= N <= *a* for *b* < *a*. + """ + ... + +def choice(sequence: Subscriptable, /) -> None: + """ + Chooses and returns one item at random from *sequence* (tuple, list or + any object that supports the subscript operation). + """ + ... + +def randint(a: int, b: int, /) -> int: + """ + Return a random integer in the range [*a*, *b*]. + """ + ... + +def getrandbits(n: int, /) -> int: + """ + Return an integer with *n* random bits (0 <= n <= 32). + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/requests/__init__.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/requests/__init__.pyi new file mode 100644 index 000000000..2ea7932fc --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/requests/__init__.pyi @@ -0,0 +1,42 @@ +""" +Module: 'requests.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def head(*args, **kwargs) -> Incomplete: + ... + +def patch(*args, **kwargs) -> Incomplete: + ... + +def post(*args, **kwargs) -> Incomplete: + ... + +def put(*args, **kwargs) -> Incomplete: + ... + +def request(*args, **kwargs) -> Incomplete: + ... + +def delete(*args, **kwargs) -> Incomplete: + ... + +def get(*args, **kwargs) -> Incomplete: + ... + + +class Response(): + def json(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + content: Incomplete ## = + text: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: + ... + diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/select.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/select.pyi new file mode 100644 index 000000000..c1893e88b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/select.pyi @@ -0,0 +1,118 @@ +""" +Wait for events on a set of streams. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/select.html + +CPython module: :mod:`python:select` https://docs.python.org/3/library/select.html . + +This module provides functions to efficiently wait for events on multiple +`streams ` (select streams which are ready for operations). + +--- +Module: 'select' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Iterable, Iterator, List, Optional, Tuple, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +POLLOUT: Final[int] = 4 +POLLIN: Final[int] = 1 +POLLHUP: Final[int] = 16 +POLLERR: Final[int] = 8 + +def select( + rlist: Iterable[Any], + wlist: Iterable[Any], + xlist: Iterable[Any], + timeout: int = -1, + /, +) -> None: + """ + Wait for activity on a set of objects. + + This function is provided by some MicroPython ports for compatibility + and is not efficient. Usage of :class:`Poll` is recommended instead. + """ + ... + +class poll: + """ + Create an instance of the Poll class. + """ + def __init__(self) -> None: ... + def register(self, obj, eventmask: Optional[Any] = None) -> None: + """ + Register `stream` *obj* for polling. *eventmask* is logical OR of: + + * ``select.POLLIN`` - data available for reading + * ``select.POLLOUT`` - more data can be written + + Note that flags like ``select.POLLHUP`` and ``select.POLLERR`` are + *not* valid as input eventmask (these are unsolicited events which + will be returned from `poll()` regardless of whether they are asked + for). This semantics is per POSIX. + + *eventmask* defaults to ``select.POLLIN | select.POLLOUT``. + + It is OK to call this function multiple times for the same *obj*. + Successive calls will update *obj*'s eventmask to the value of + *eventmask* (i.e. will behave as `modify()`). + """ + ... + def unregister(self, obj) -> Incomplete: + """ + Unregister *obj* from polling. + """ + ... + def modify(self, obj, eventmask) -> None: + """ + Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError` + is raised with error of ENOENT. + """ + ... + def poll(self, timeout=-1, /) -> List: + """ + Wait for at least one of the registered objects to become ready or have an + exceptional condition, with optional timeout in milliseconds (if *timeout* + arg is not specified or -1, there is no timeout). + + Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in + tuple, depending on a platform and version, so don't assume that its size is 2. + The ``event`` element specifies which events happened with a stream and + is a combination of ``select.POLL*`` constants described above. Note that + flags ``select.POLLHUP`` and ``select.POLLERR`` can be returned at any time + (even if were not asked for), and must be acted on accordingly (the + corresponding stream unregistered from poll and likely closed), because + otherwise all further invocations of `poll()` may return immediately with + these flags set for this stream again. + + In case of timeout, an empty list is returned. + + Admonition:Difference to CPython + :class: attention + + Tuples returned may contain more than 2 elements as described above. + """ + ... + def ipoll(self, timeout=-1, flags=0, /) -> Iterator[Tuple]: + """ + Like :meth:`poll.poll`, but instead returns an iterator which yields a + `callee-owned tuple`. This function provides an efficient, allocation-free + way to poll on streams. + + If *flags* is 1, one-shot behaviour for events is employed: streams for + which events happened will have their event masks automatically reset + (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream + won't be processed until new mask is set with `poll.modify()`. This + behaviour is useful for asynchronous I/O schedulers. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/socket.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/socket.pyi new file mode 100644 index 000000000..9acb73654 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/socket.pyi @@ -0,0 +1,426 @@ +""" +Socket module. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/socket.html + +CPython module: :mod:`python:socket` https://docs.python.org/3/library/socket.html . + +This module provides access to the BSD socket interface. + +Admonition:Difference to CPython + :class: attention + + For efficiency and consistency, socket objects in MicroPython implement a `stream` + (file-like) interface directly. In CPython, you need to convert a socket to + a file-like object using `makefile()` method. This method is still supported + by MicroPython (but is a no-op), so where compatibility with CPython matters, + be sure to use it. + +Socket address format(s) +------------------------ + +The native socket address format of the ``socket`` module is an opaque data type +returned by `getaddrinfo` function, which must be used to resolve textual address +(including numeric addresses):: + + sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1] + # You must use getaddrinfo() even for numeric addresses + sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1] + # Now you can use that address + sock.connect(sockaddr) + +Using `getaddrinfo` is the most efficient (both in terms of memory and processing +power) and portable way to work with addresses. + +However, ``socket`` module (note the difference with native MicroPython +``socket`` module described here) provides CPython-compatible way to specify +addresses using tuples, as described below. Note that depending on a +:term:`MicroPython port`, ``socket`` module can be builtin or need to be +installed from `micropython-lib` (as in the case of :term:`MicroPython Unix port`), +and some ports still accept only numeric addresses in the tuple format, +and require to use `getaddrinfo` function to resolve domain names. + +Summing up: + +* Always use `getaddrinfo` when writing portable applications. +* Tuple addresses described below can be used as a shortcut for + quick hacks and interactive use, if your port supports them. + +Tuple address format for ``socket`` module: + +* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with + dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and + integer port number in the range 1-65535. Note the domain names are not + accepted as *ipv4_address*, they should be resolved first using + `socket.getaddrinfo()`. +* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address* + is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``, + and *port* is an integer port number in the range 1-65535. *flowinfo* + must be 0. *scopeid* is the interface scope identifier for link-local + addresses. Note the domain names are not accepted as *ipv6_address*, + they should be resolved first using `socket.getaddrinfo()`. Availability + of IPv6 support depends on a :term:`MicroPython port`. + +--- +Module: 'socket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Literal, Tuple, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +SOCK_RAW: Final[int] = 3 +SOCK_STREAM: Final[int] = 1 +"""Socket types.""" +SOCK_DGRAM: Final[int] = 2 +"""Socket types.""" +MSG_PEEK: Final[int] = 1 +SO_REUSEADDR: Final[int] = 4 +SOL_SOCKET: Final[int] = 1 +SO_BROADCAST: Final[int] = 32 +TCP_NODELAY: Final[int] = 64 +AF_INET6: Final[int] = 10 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +IPPROTO_IP: Final[int] = 0 +AF_INET: Final[int] = 2 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +MSG_DONTWAIT: Final[int] = 2 +IP_DROP_MEMBERSHIP: Final[int] = 1025 +IPPROTO_TCP: Final[int] = 6 +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IP_ADD_MEMBERSHIP: Final[int] = 1024 +IPPROTO_UDP: Incomplete +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IPPROTO_SEC: Incomplete +"""Special protocol value to create SSL-compatible socket.""" +_Address: TypeAlias = tuple[str, int] | tuple[str, int, int, int] | str +Socket: TypeAlias = socket + +def reset(*args, **kwargs) -> Incomplete: ... +def print_pcbs(*args, **kwargs) -> Incomplete: ... +def getaddrinfo( + host: str, + port: int, + af: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, + /, +) -> list[tuple[int, int, int, str, tuple[str, int] | tuple[str, int, int, int]]]: + """ + Translate the host/port argument into a sequence of 5-tuples that contain all the + necessary arguments for creating a socket connected to that service. Arguments + *af*, *type*, and *proto* (which have the same meaning as for the `socket()` function) + can be used to filter which kind of addresses are returned. If a parameter is not + specified or zero, all combinations of addresses can be returned (requiring + filtering on the user side). + + The resulting list of 5-tuples has the following structure:: + + (family, type, proto, canonname, sockaddr) + + The following example shows how to connect to a given url:: + + s = socket.socket() + # This assumes that if "type" is not specified, an address for + # SOCK_STREAM will be returned, which may be not true + s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1]) + + Recommended use of filtering params:: + + s = socket.socket() + # Guaranteed to return an address which can be connect'ed to for + # stream operation. + s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1]) + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.gaierror`` exception (`OSError` subclass) in case + of error in this function. MicroPython doesn't have ``socket.gaierror`` + and raises OSError directly. Note that error numbers of `getaddrinfo()` + form a separate namespace and may not match error numbers from + the :mod:`errno` module. To distinguish `getaddrinfo()` errors, they are + represented by negative numbers, whereas standard system errors are + positive numbers (error numbers are accessible using ``e.args[0]`` property + from an exception object). The use of negative values is a provisional + detail which may change in the future. + """ + ... + +def callback(*args, **kwargs) -> Incomplete: ... + +class socket: + """ + A unix like socket, for more information see module ``socket``'s description. + + The name, `Socket`, used for typing is not the same as the runtime name, `socket` (note lowercase `s`). + The reason for this difference is that the runtime uses `socket` as both a class name and as a method name and + this is not possible within code written entirely in Python and therefore not possible within typing code. + """ + def recvfrom(self, bufsize: int, /) -> Tuple: + """ + Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a + bytes object representing the data received and *address* is the address of the socket sending + the data. + + See the `recv` function for an explanation of the optional *flags* argument. + """ + ... + def recv(self, bufsize: int, /) -> bytes: + """ + Receive data from the socket. The return value is a bytes object representing the data + received. The maximum amount of data to be received at once is specified by bufsize. + + Most ports support the optional *flags* argument. Available *flags* are defined as constants + in the socket module and have the same meaning as in CPython. ``MSG_PEEK`` and ``MSG_DONTWAIT`` + are supported on all ports which accept the *flags* argument. + """ + ... + + @overload + def makefile(self, mode: Literal["rb", "wb", "rwb"] = "rb", buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + + @overload + def makefile(self, mode: str, buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + def listen(self, backlog: int = ..., /) -> None: + """ + Enable a server to accept connections. If *backlog* is specified, it must be at least 0 + (if it's lower, it will be set to 0); and specifies the number of unaccepted connections + that the system will allow before refusing new connections. If not specified, a default + reasonable value is chosen. + """ + ... + def settimeout(self, value: float | None, /) -> None: + """ + **Note**: Not every port supports this method, see below. + + Set a timeout on blocking socket operations. The value argument can be a nonnegative floating + point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations + will raise an `OSError` exception if the timeout period value has elapsed before the operation has + completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket + is put in blocking mode. + + Not every :term:`MicroPython port` supports this method. A more portable and + generic solution is to use `select.poll` object. This allows to wait on + multiple objects at the same time (and not just on sockets, but on generic + `stream` objects which support polling). Example:: + + # Instead of: + s.settimeout(1.0) # time in seconds + s.read(10) # may timeout + + # Use: + poller = select.poll() + poller.register(s, select.POLLIN) + res = poller.poll(1000) # time in milliseconds + if not res: + # s is still not ready for input, i.e. operation timed out + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.timeout`` exception in case of timeout, + which is an `OSError` subclass. MicroPython raises an OSError directly + instead. If you use ``except OSError:`` to catch the exception, + your code will work both in MicroPython and CPython. + """ + ... + def sendall(self, bytes: AnyReadableBuf, /) -> int: + """ + Send all data to the socket. The socket must be connected to a remote socket. + Unlike `send()`, this method will try to send all of data, by sending data + chunk by chunk consecutively. + + The behaviour of this method on non-blocking sockets is undefined. Due to this, + on MicroPython, it's recommended to use `write()` method instead, which + has the same "no short writes" policy for blocking sockets, and will return + number of bytes sent on non-blocking sockets. + """ + ... + def setsockopt(self, level: int, optname: int, value: AnyReadableBuf | int, /) -> None: + """ + Set the value of the given socket option. The needed symbolic constants are defined in the + socket module (SO_* etc.). The *value* can be an integer or a bytes-like object representing + a buffer. + """ + ... + def setblocking(self, value: bool, /) -> None: + """ + Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking, + else to blocking mode. + + This method is a shorthand for certain `settimeout()` calls: + + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)`` + """ + ... + def sendto(self, bytes: AnyReadableBuf, address: _Address, /) -> None: + """ + Send data to the socket. The socket should not be connected to a remote socket, since the + destination socket is specified by *address*. + """ + ... + def readline(self) -> bytes: + """ + Read a line, ending in a newline character. + + Return value: the line read. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def read(self) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + + @overload + def read(self, size: int, /) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + def close(self) -> None: + """ + Mark the socket closed and release all resources. Once that happens, all future operations + on the socket object will fail. The remote end will receive EOF indication if + supported by protocol. + + Sockets are automatically closed when they are garbage-collected, but it is recommended + to `close()` them explicitly as soon you finished working with them. + """ + ... + def connect(self, address: _Address | bytes, /) -> None: + """ + Connect to a remote socket at *address*. + """ + ... + def send(self, bytes: AnyReadableBuf, /) -> int: + """ + Send data to the socket. The socket must be connected to a remote socket. + Returns number of bytes sent, which may be smaller than the length of data + ("short write"). + """ + ... + def bind(self, address: _Address | bytes, /) -> None: + """ + Bind the socket to *address*. The socket must not already be bound. + """ + ... + def accept(self) -> Tuple: + """ + Accept a connection. The socket must be bound to an address and listening for connections. + The return value is a pair (conn, address) where conn is a new socket object usable to send + and receive data on the connection, and address is the address bound to the socket on the + other end of the connection. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the buffer of bytes to the socket. This function will try to + write all data to a socket (no "short writes"). This may be not possible + with a non-blocking socket though, and returned value will be less than + the length of *buf*. + + Return value: number of bytes written. + """ + ... + def __init__( + self, + af: int = AF_INET, + type: int = SOCK_STREAM, + proto: int = IPPROTO_TCP, + /, + ) -> None: + """ + Create a new socket using the given address family, socket type and + protocol number. Note that specifying *proto* in most cases is not + required (and not recommended, as some MicroPython ports may omit + ``IPPROTO_*`` constants). Instead, *type* argument will select needed + protocol automatically:: + + # Create STREAM TCP socket + socket(AF_INET, SOCK_STREAM) + # Create DGRAM UDP socket + socket(AF_INET, SOCK_DGRAM) + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/time.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/time.pyi new file mode 100644 index 000000000..1f091db69 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/time.pyi @@ -0,0 +1,306 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. + +--- +Module: 'time' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def ticks_diff(ticks1: _Ticks, ticks2: _Ticks, /) -> int: + """ + Measure ticks difference between values returned from `ticks_ms()`, `ticks_us()`, + or `ticks_cpu()` functions, as a signed value which may wrap around. + + The argument order is the same as for subtraction + operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. + However, values returned by `ticks_ms()`, etc. functions may wrap around, so + directly using subtraction on them will produce incorrect result. That is why + `ticks_diff()` is needed, it implements modular (or more specifically, ring) + arithmetic to produce correct result even for wrap-around values (as long as they not + too distant in between, see below). The function returns **signed** value in the range + [*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for + two's-complement signed binary integers). If the result is negative, it means that + *ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that + *ticks1* occurred after *ticks2*. This holds **only** if *ticks1* and *ticks2* + are apart from each other for no more than *TICKS_PERIOD/2-1* ticks. If that does + not hold, incorrect result will be returned. Specifically, if two tick values are + apart for *TICKS_PERIOD/2-1* ticks, that value will be returned by the function. + However, if *TICKS_PERIOD/2* of real-time ticks has passed between them, the + function will return *-TICKS_PERIOD/2* instead, i.e. result value will wrap around + to the negative range of possible values. + + Informal rationale of the constraints above: Suppose you are locked in a room with no + means to monitor passing of time except a standard 12-notch clock. Then if you look at + dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a + long sleep), then once you finally look again, it may seem to you that only 1 hour + has passed. To avoid this mistake, just look at the clock regularly. Your application + should do the same. "Too long sleep" metaphor also maps directly to application + behaviour: don't let your application run any single task for too long. Run tasks + in steps, and do time-keeping in between. + + `ticks_diff()` is designed to accommodate various usage patterns, among them: + + * Polling with timeout. In this case, the order of events is known, and you will deal + only with positive results of `ticks_diff()`:: + + # Wait for GPIO pin to be asserted, but at most 500us + start = time.ticks_us() + while pin.value() == 0: + if time.ticks_diff(time.ticks_us(), start) > 500: + raise TimeoutError + + * Scheduling events. In this case, `ticks_diff()` result may be negative + if an event is overdue:: + + # This code snippet is not optimized + now = time.ticks_ms() + scheduled_time = task.scheduled_time() + if ticks_diff(scheduled_time, now) > 0: + print("Too early, let's nap") + sleep_ms(ticks_diff(scheduled_time, now)) + task.run() + elif ticks_diff(scheduled_time, now) == 0: + print("Right at time!") + task.run() + elif ticks_diff(scheduled_time, now) < 0: + print("Oops, running late, tell task to run faster!") + task.run(run_faster=true) + + Note: Do not pass `time()` values to `ticks_diff()`, you should use + normal mathematical operations on them. But note that `time()` may (and will) + also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem . + """ + ... + +def ticks_add(ticks: _Ticks, delta: int, /) -> _Ticks: + """ + Offset ticks value by a given number, which can be either positive or negative. + Given a *ticks* value, this function allows to calculate ticks value *delta* + ticks before or after it, following modular-arithmetic definition of tick values + (see `ticks_ms()` above). *ticks* parameter must be a direct result of call + to `ticks_ms()`, `ticks_us()`, or `ticks_cpu()` functions (or from previous + call to `ticks_add()`). However, *delta* can be an arbitrary integer number + or numeric expression. `ticks_add()` is useful for calculating deadlines for + events/tasks. (Note: you must use `ticks_diff()` function to work with + deadlines.) + + Examples:: + + # Find out what ticks value there was 100ms ago + print(ticks_add(time.ticks_ms(), -100)) + + # Calculate deadline for operation and test for it + deadline = ticks_add(time.ticks_ms(), 200) + while ticks_diff(deadline, time.ticks_ms()) > 0: + do_a_little_of_something() + + # Find out TICKS_MAX used by this port + print(ticks_add(0, -1)) + """ + ... + +def ticks_cpu() -> _TicksCPU: + """ + Similar to `ticks_ms()` and `ticks_us()`, but with the highest possible resolution + in the system. This is usually CPU clocks, and that's why the function is named that + way. But it doesn't have to be a CPU clock, some other timing source available in a + system (e.g. high-resolution timer) can be used instead. The exact timing unit + (resolution) of this function is not specified on ``time`` module level, but + documentation for a specific port may provide more specific information. This + function is intended for very fine benchmarking or very tight real-time loops. + Avoid using it in portable code. + + Availability: Not every port implements this function. + """ + ... + +def time() -> int: + """ + Returns the number of seconds, as an integer, since the Epoch, assuming that + underlying RTC is set and maintained as described above. If an RTC is not set, this + function returns number of seconds since a port-specific reference point in time (for + embedded boards without a battery-backed RTC, usually since power up or reset). If you + want to develop portable MicroPython application, you should not rely on this function + to provide higher than second precision. If you need higher precision, absolute + timestamps, use `time_ns()`. If relative times are acceptable then use the + `ticks_ms()` and `ticks_us()` functions. If you need calendar time, `gmtime()` or + `localtime()` without an argument is a better choice. + + Admonition:Difference to CPython + :class: attention + + In CPython, this function returns number of + seconds since Unix epoch, 1970-01-01 00:00 UTC, as a floating-point, + usually having microsecond precision. With MicroPython, only Unix port + uses the same Epoch, and if floating-point precision allows, + returns sub-second precision. Embedded hardware usually doesn't have + floating-point precision to represent both long time ranges and subsecond + precision, so they use integer value with second precision. Some embedded + hardware also lacks battery-powered RTC, so returns number of seconds + since last power-up or from other relative, hardware-specific point + (e.g. reset). + """ + ... + +def ticks_ms() -> int: + """ + Returns an increasing millisecond counter with an arbitrary reference point, that + wraps around after some value. + + The wrap-around value is not explicitly exposed, but we will + refer to it as *TICKS_MAX* to simplify discussion. Period of the values is + *TICKS_PERIOD = TICKS_MAX + 1*. *TICKS_PERIOD* is guaranteed to be a power of + two, but otherwise may differ from port to port. The same period value is used + for all of `ticks_ms()`, `ticks_us()`, `ticks_cpu()` functions (for + simplicity). Thus, these functions will return a value in range [*0* .. + *TICKS_MAX*], inclusive, total *TICKS_PERIOD* values. Note that only + non-negative values are used. For the most part, you should treat values returned + by these functions as opaque. The only operations available for them are + `ticks_diff()` and `ticks_add()` functions described below. + + Note: Performing standard mathematical operations (+, -) or relational + operators (<, <=, >, >=) directly on these value will lead to invalid + result. Performing mathematical operations and then passing their results + as arguments to `ticks_diff()` or `ticks_add()` will also lead to + invalid results from the latter functions. + """ + ... + +def ticks_us() -> _TicksUs: + """ + Just like `ticks_ms()` above, but in microseconds. + """ + ... + +def time_ns() -> int: + """ + Similar to `time()` but returns nanoseconds since the Epoch, as an integer (usually + a big integer, so will allocate on the heap). + """ + ... + +def localtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_us(us: int, /) -> None: + """ + Delay for given number of microseconds, should be positive or 0. + + This function attempts to provide an accurate delay of at least *us* + microseconds, but it may take longer if the system has other higher priority + processing to perform. + """ + ... + +def gmtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_ms(ms: int, /) -> None: + """ + Delay for given number of milliseconds, should be positive or 0. + + This function will delay for at least the given number of milliseconds, but + may take longer than that if other processing must take place, for example + interrupt handlers or other threads. Passing in 0 for *ms* will still allow + this other processing to occur. Use `sleep_us()` for more precise delays. + """ + ... + +def mktime(local_time: _TimeTuple, /) -> int: + """ + This is inverse function of localtime. It's argument is a full 8-tuple + which expresses a time as per localtime. It returns an integer which is + the number of seconds since the time epoch. + """ + ... + +def sleep(seconds: float, /) -> None: + """ + Sleep for the given number of seconds. Some boards may accept *seconds* as a + floating-point number to sleep for a fractional number of seconds. Note that + other boards may not accept a floating-point argument, for compatibility with + them use `sleep_ms()` and `sleep_us()` functions. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/tls.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/tls.pyi new file mode 100644 index 000000000..34f93f51e --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/tls.pyi @@ -0,0 +1,26 @@ +""" +Module: 'tls' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +PROTOCOL_TLS_SERVER: Final[int] = 1 +PROTOCOL_DTLS_CLIENT: Final[int] = 2 +PROTOCOL_DTLS_SERVER: Final[int] = 3 +PROTOCOL_TLS_CLIENT: Final[int] = 0 +MBEDTLS_VERSION: Final[str] = "Mbed TLS 3.6.2" +CERT_NONE: Final[int] = 0 +CERT_OPTIONAL: Final[int] = 1 +CERT_REQUIRED: Final[int] = 2 + +class SSLContext: + def load_verify_locations(self, *args, **kwargs) -> Incomplete: ... + def set_ciphers(self, *args, **kwargs) -> Incomplete: ... + def wrap_socket(self, *args, **kwargs) -> Incomplete: ... + def load_cert_chain(self, *args, **kwargs) -> Incomplete: ... + def get_ciphers(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uarray.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uarray.pyi new file mode 100644 index 000000000..e5c0fe438 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uarray.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to array +from array import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uasyncio.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uasyncio.pyi new file mode 100644 index 000000000..3d69c52f2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uasyncio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to asyncio +from asyncio import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ubinascii.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ubinascii.pyi new file mode 100644 index 000000000..3a77380ad --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ubinascii.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to binascii +from binascii import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ubluetooth.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ubluetooth.pyi new file mode 100644 index 000000000..4046c2c75 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ubluetooth.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to bluetooth +from bluetooth import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ucollections.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ucollections.pyi new file mode 100644 index 000000000..5b2ffea32 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ucollections.pyi @@ -0,0 +1,15 @@ +""" +Collection and container types. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/collections.html + +CPython module: :mod:`python:collections` https://docs.python.org/3/library/collections.html . + +This module implements advanced collection and container types to +hold/accumulate various objects. + +--- +Module: 'ucollections' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# import module from stdlib/module +from collections import * \ No newline at end of file diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ucryptolib.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ucryptolib.pyi new file mode 100644 index 000000000..6b8b56a68 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ucryptolib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to cryptolib +from cryptolib import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uctypes.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uctypes.pyi new file mode 100644 index 000000000..a74802960 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uctypes.pyi @@ -0,0 +1,164 @@ +""" +Access binary data in a structured way. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/uctypes.html + +This module implements "foreign data interface" for MicroPython. The idea +behind it is similar to CPython's ``ctypes`` modules, but the actual API is +different, streamlined and optimized for small size. The basic idea of the +module is to define data structure layout with about the same power as the +C language allows, and then access it using familiar dot-syntax to reference +sub-fields. + +--- +Module: 'uctypes' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Tuple, Any, Final, Generator +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +VOID: Final[int] = 0 +"""\ +``VOID`` is an alias for ``UINT8``, and is provided to conveniently define +C's void pointers: ``(uctypes.PTR, uctypes.VOID)``. +""" +NATIVE: Final[int] = 2 +"""\ +Layout type for a native structure - with data endianness and alignment +conforming to the ABI of the system on which MicroPython runs. +""" +PTR: Final[int] = 536870912 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +SHORT: Final[int] = 402653184 +LONGLONG: Final[int] = 939524096 +INT8: Final[int] = 134217728 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +LITTLE_ENDIAN: Final[int] = 0 +"""\ +Layout type for a little-endian packed structure. (Packed means that every +field occupies exactly as many bytes as defined in the descriptor, i.e. +the alignment is 1). +""" +LONG: Final[int] = 671088640 +UINT: Final[int] = 536870912 +ULONG: Final[int] = 536870912 +ULONGLONG: Final[int] = 805306368 +USHORT: Final[int] = 268435456 +UINT8: Final[int] = 0 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT16: Final[int] = 268435456 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT32: Final[int] = 536870912 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT64: Final[int] = 805306368 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT64: Final[int] = 939524096 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +BFUINT16: Final[int] = -805306368 +BFUINT32: Final[int] = -536870912 +BFUINT8: Final[int] = -1073741824 +BFINT8: Final[int] = -939524096 +ARRAY: Final[int] = -1073741824 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +BFINT16: Final[int] = -671088640 +BFINT32: Final[int] = -402653184 +BF_LEN: Final[int] = 22 +INT: Final[int] = 671088640 +INT16: Final[int] = 402653184 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT32: Final[int] = 671088640 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +FLOAT64: Final[int] = -134217728 +"""Floating-point types for structure descriptors.""" +BF_POS: Final[int] = 17 +BIG_ENDIAN: Final[int] = 1 +"""Layout type for a big-endian packed structure.""" +FLOAT32: Final[int] = -268435456 +"""Floating-point types for structure descriptors.""" +_property: TypeAlias = Incomplete +_descriptor: TypeAlias = Tuple | Dict + +def sizeof(struct: struct | _descriptor | dict, layout_type: int = NATIVE, /) -> int: + """ + Return size of data structure in bytes. The *struct* argument can be + either a structure class or a specific instantiated structure object + (or its aggregate field). + """ + ... + +def bytes_at(addr: int, size: int, /) -> bytes: + """ + Capture memory at the given address and size as bytes object. As bytes + object is immutable, memory is actually duplicated and copied into + bytes object, so if memory contents change later, created object + retains original value. + """ + ... + +def bytearray_at(addr: int, size: int, /) -> bytearray: + """ + Capture memory at the given address and size as bytearray object. + Unlike bytes_at() function above, memory is captured by reference, + so it can be both written too, and you will access current value + at the given memory address. + """ + ... + +def addressof(obj: AnyReadableBuf, /) -> int: + """ + Return address of an object. Argument should be bytes, bytearray or + other object supporting buffer protocol (and address of this buffer + is what actually returned). + """ + ... + +class struct: + """ + Module contents + --------------- + """ + def __init__(self, addr: int | struct, descriptor: _descriptor, layout_type: int = NATIVE, /) -> None: + """ + Instantiate a "foreign data structure" object based on structure address in + memory, descriptor (encoded as a dictionary), and layout type (see below). + """ + ... + @mp_available() # force push + def __getattr__(self, a): ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uerrno.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uerrno.pyi new file mode 100644 index 000000000..8d34ba6b7 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uerrno.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to errno +from errno import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uhashlib.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uhashlib.pyi new file mode 100644 index 000000000..8b4b7bc77 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uhashlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to hashlib +from hashlib import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uheapq.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uheapq.pyi new file mode 100644 index 000000000..71c066fcf --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uheapq.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to heapq +from heapq import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uio.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uio.pyi new file mode 100644 index 000000000..514a4f945 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to io +from io import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ujson.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ujson.pyi new file mode 100644 index 000000000..0de669254 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ujson.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to json +from json import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/umachine.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/umachine.pyi new file mode 100644 index 000000000..e1fdb35a4 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/umachine.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to machine +from machine import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uos.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uos.pyi new file mode 100644 index 000000000..8c99e764b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uos.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to os +from os import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uplatform.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uplatform.pyi new file mode 100644 index 000000000..22ad247bf --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uplatform.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to platform +from platform import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/urandom.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/urandom.pyi new file mode 100644 index 000000000..b912f0793 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/urandom.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to random +from random import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ure.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ure.pyi new file mode 100644 index 000000000..dbe8b6a52 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ure.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to re +from re import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/urequests.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/urequests.pyi new file mode 100644 index 000000000..3ef9fce15 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/urequests.pyi @@ -0,0 +1,25 @@ +""" +Module: 'urequests' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def head(*args, **kwargs) -> Incomplete: ... +def patch(*args, **kwargs) -> Incomplete: ... +def post(*args, **kwargs) -> Incomplete: ... +def put(*args, **kwargs) -> Incomplete: ... +def request(*args, **kwargs) -> Incomplete: ... +def delete(*args, **kwargs) -> Incomplete: ... +def get(*args, **kwargs) -> Incomplete: ... + +class Response: + def json(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + + content: Incomplete ## = + text: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uselect.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uselect.pyi new file mode 100644 index 000000000..a543041c4 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uselect.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to select +from select import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/usocket.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/usocket.pyi new file mode 100644 index 000000000..140590c29 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/usocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to socket +from socket import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ussl.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ussl.pyi new file mode 100644 index 000000000..3115761c4 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ussl.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to ssl +from ssl import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ustruct.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ustruct.pyi new file mode 100644 index 000000000..0f7fb657a --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ustruct.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to struct +from struct import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/usys.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/usys.pyi new file mode 100644 index 000000000..298d7a8ac --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/usys.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to sys +from sys import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/utime.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/utime.pyi new file mode 100644 index 000000000..1f972a5b6 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/utime.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to time +from time import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uwebsocket.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uwebsocket.pyi new file mode 100644 index 000000000..afa801ba2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uwebsocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to websocket +from websocket import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uzlib.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uzlib.pyi new file mode 100644 index 000000000..5fad9a23c --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/uzlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to zlib +from zlib import * diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/vfs.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/vfs.pyi new file mode 100644 index 000000000..97e4941f1 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/vfs.pyi @@ -0,0 +1,240 @@ +""" +Virtual filesystem control. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/vfs.html + +The ``vfs`` module contains functions for creating filesystem objects and +mounting/unmounting them in the Virtual Filesystem. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +--- +Module: 'vfs' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _BlockDeviceProtocol +from abc import ABC, abstractmethod +from typing import List, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def umount(mount_point: Incomplete) -> Incomplete: + """ + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + """ + ... + +@overload +def mount(fsobj, mount_point: str, *, readonly: bool = False) -> None: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +@overload +def mount() -> List[tuple[Incomplete, str]]: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +class VfsLfs2: + """ + Create a filesystem object that uses the `littlefs v2 filesystem format`_. + Storage of the littlefs filesystem is provided by *block_dev*, which must + support the :ref:`extended interface `. + Objects created by this constructor can be mounted using :func:`mount`. + + The *mtime* argument enables modification timestamps for files, stored using + littlefs attributes. This option can be disabled or enabled differently each + mount time and timestamps will only be added or updated if *mtime* is enabled, + otherwise the timestamps will remain untouched. Littlefs v2 filesystems without + timestamps will work without reformatting and timestamps will be added + transparently to existing files once they are opened for writing. When *mtime* + is enabled `os.stat` on files without timestamps will return 0 for the timestamp. + + See :ref:`filesystem` for more information. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32) -> None: + """ + Build a Lfs2 filesystem on *block_dev*. + + ``Note:`` There are reports of littlefs v2 failing in certain situations, + for details see `littlefs issue 295`_. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32, mtime=True) -> None: ... + +class VfsFat: + """ + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev) -> None: + """ + Build a FAT filesystem on *block_dev*. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev) -> None: ... + +class AbstractBlockDev: + # + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: ... + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + ... + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + ... + + @abstractmethod + @overload + def ioctl(self, op: int, arg) -> int | None: ... + # + @abstractmethod + @overload + def ioctl(self, op: int) -> int | None: + """ + Control the block device and query its parameters. The operation to + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 5 -- get the number of bytes in a block, should return an integer, + or ``None`` in which case the default value of 512 is used + (*arg* is unused) + - 6 -- erase a block, *arg* is the block number to erase + + As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs + ``ioctl(6, ...)`` must also be intercepted. The need for others is + hardware dependent. + + Prior to any call to ``writeblocks(block, ...)`` littlefs issues + ``ioctl(6, block)``. This enables a device driver to erase the block + prior to a write if the hardware requires it. Alternatively a driver + might intercept ``ioctl(6, block)`` and return 0 (success). In this case + the driver assumes responsibility for detecting the need for erasure. + + Unless otherwise stated ``ioctl(op, arg)`` can return ``None``. + Consequently an implementation can ignore unused values of ``op``. Where + ``op`` is intercepted, the return value for operations 4 and 5 are as + detailed above. Other operations should return 0 on success and non-zero + for failure, with the value returned being an ``OSError`` errno code. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/websocket.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/websocket.pyi new file mode 100644 index 000000000..62bf8e79b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/websocket.pyi @@ -0,0 +1,17 @@ +""" +Module: 'websocket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class websocket: + def readline(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/_onewire.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/_onewire.pyi new file mode 100644 index 000000000..2e9c634f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/_onewire.pyi @@ -0,0 +1,15 @@ +""" +Module: '_onewire' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def reset(*args, **kwargs) -> Incomplete: ... +def writebyte(*args, **kwargs) -> Incomplete: ... +def writebit(*args, **kwargs) -> Incomplete: ... +def crc8(*args, **kwargs) -> Incomplete: ... +def readbyte(*args, **kwargs) -> Incomplete: ... +def readbit(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/binascii.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/binascii.pyi new file mode 100644 index 000000000..3bea9ae53 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/binascii.pyi @@ -0,0 +1,61 @@ +""" +Binary/ASCII conversions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/binascii.html + +CPython module: :mod:`python:binascii` https://docs.python.org/3/library/binascii.html . + +This module implements conversions between binary data and various +encodings of it in ASCII form (in both directions). + +--- +Module: 'binascii' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any, Optional +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def crc32(data, value: Optional[Any] = None) -> Incomplete: + """ + Compute CRC-32, the 32-bit checksum of *data*, starting with an initial CRC + of *value*. The default initial CRC is zero. The algorithm is consistent + with the ZIP file checksum. + """ + ... + +def hexlify(data: bytes, sep: str | bytes = ..., /) -> bytes: + """ + Convert the bytes in the *data* object to a hexadecimal representation. + Returns a bytes object. + + If the additional argument *sep* is supplied it is used as a separator + between hexadecimal values. + """ + ... + +def unhexlify(data: str | bytes, /) -> bytes: + """ + Convert hexadecimal data to binary representation. Returns bytes string. + (i.e. inverse of hexlify) + """ + ... + +def b2a_base64(data: bytes, /) -> bytes: + """ + Encode binary data in base64 format, as in `RFC 3548 + `_. Returns the encoded data + followed by a newline character if newline is true, as a bytes object. + """ + ... + +def a2b_base64(data: str | bytes, /) -> bytes: + """ + Decode base64-encoded data, ignoring invalid characters in the input. + Conforms to `RFC 2045 s.6.8 `_. + Returns a bytes object. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/cmath.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/cmath.pyi new file mode 100644 index 000000000..a20e1eea1 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/cmath.pyi @@ -0,0 +1,84 @@ +""" +Mathematical functions for complex numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/cmath.html + +CPython module: :mod:`python:cmath` https://docs.python.org/3/library/cmath.html . + +The ``cmath`` module provides some basic mathematical functions for +working with complex numbers. + +Availability: not available on WiPy and ESP8266. Floating point support +required for this module. + +--- +Module: 'cmath' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsComplex, SupportsFloat, SupportsIndex, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_C: TypeAlias = SupportsFloat | SupportsComplex | SupportsIndex | complex + +e: float = 2.718281828459045 +"""base of the natural logarithm""" +pi: float = 3.141592653589793 +"""the ratio of a circle's circumference to its diameter""" + +def polar(z: _C, /) -> Tuple: + """ + Returns, as a tuple, the polar form of ``z``. + """ + ... + +def sqrt(z: _C, /) -> complex: + """ + Return the square-root of ``z``. + """ + ... + +def rect(r: float, phi: float, /) -> float: + """ + Returns the complex number with modulus ``r`` and phase ``phi``. + """ + ... + +def sin(z: _C, /) -> float: + """ + Return the sine of ``z``. + """ + ... + +def exp(z: _C, /) -> float: + """ + Return the exponential of ``z``. + """ + ... + +def cos(z: _C, /) -> float: + """ + Return the cosine of ``z``. + """ + ... + +def phase(z: _C, /) -> float: + """ + Returns the phase of the number ``z``, in the range (-pi, +pi]. + """ + ... + +def log(z: _C, /) -> float: + """ + Return the natural logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... + +def log10(z: _C, /) -> float: + """ + Return the base-10 logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/cryptolib.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/cryptolib.pyi new file mode 100644 index 000000000..e6dd78a9d --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/cryptolib.pyi @@ -0,0 +1,165 @@ +""" +Cryptographic ciphers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/cryptolib.html + +--- +Module: 'cryptolib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +class aes: + """ + .. class:: aes + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, IV: AnyReadableBuf, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, IV: AnyReadableBuf, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/deflate.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/deflate.pyi new file mode 100644 index 000000000..9366f529f --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/deflate.pyi @@ -0,0 +1,89 @@ +""" +Deflate compression & decompression. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/deflate.html + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ +(commonly used in the zlib library and gzip archiver). + +**Availability:** + +* Added in MicroPython v1.21. + +* Decompression: Enabled via the ``MICROPY_PY_DEFLATE`` build option, on by default + on ports with the "extra features" level or higher (which is most boards). + +* Compression: Enabled via the ``MICROPY_PY_DEFLATE_COMPRESS`` build option, on + by default on ports with the "full features" level or higher (generally this means + you need to build your own firmware to enable this). + +--- +Module: 'deflate' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +GZIP: Final[int] = 3 +"""Supported values for the *format* parameter.""" +RAW: Final[int] = 1 +"""Supported values for the *format* parameter.""" +ZLIB: Final[int] = 2 +"""Supported values for the *format* parameter.""" +AUTO: Final[int] = 0 +"""Supported values for the *format* parameter.""" + +class DeflateIO: + """ + This class can be used to wrap a *stream* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + The *stream* must be a blocking stream. Non-blocking streams are currently + not supported. + + The *format* can be set to any of the constants defined below, and defaults + to ``AUTO`` which for decompressing will auto-detect gzip or zlib streams, + and for compressing it will generate a raw stream. + + The *wbits* parameter sets the base-2 logarithm of the DEFLATE dictionary + window size. So for example, setting *wbits* to ``10`` sets the window size + to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to + window sizes of 32 to 32k bytes). + + If *wbits* is set to ``0`` (the default), then for compression a window size + of 256 bytes will be used (as if *wbits* was set to 8). For decompression, it + depends on the format: + + * ``RAW`` will use 256 bytes (corresponding to *wbits* set to 8). + * ``ZLIB`` (or ``AUTO`` with zlib detected) will use the value from the zlib + header. + * ``GZIP`` (or ``AUTO`` with gzip detected) will use 32 kilobytes + (corresponding to *wbits* set to 15). + + See the :ref:`window size ` notes below for more information + about the window size, zlib, and gzip streams. + + If *close* is set to ``True`` then the underlying stream will be closed + automatically when the :class:`deflate.DeflateIO` stream is closed. This is + useful if you want to return a :class:`deflate.DeflateIO` stream that wraps + another stream and not have the caller need to know about managing the + underlying stream. + + If compression is enabled, a given :class:`deflate.DeflateIO` instance + supports both reading and writing. For example, a bidirectional stream like + a socket can be wrapped, which allows for compression/decompression in both + directions. + """ + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, stream, format=AUTO, wbits=0, close=False, /) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/dht.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/dht.pyi new file mode 100644 index 000000000..3a5da285f --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/dht.pyi @@ -0,0 +1,26 @@ +""" +Module: 'dht' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def dht_readinto(*args, **kwargs) -> Incomplete: ... + +class DHTBase: + def measure(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT22: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT11: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/doc_stubs.json b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/doc_stubs.json new file mode 100644 index 000000000..adcb4b944 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/doc_stubs.json @@ -0,0 +1,476 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "-", + "platform": "-", + "machine": "micropython", + "firmware": "micropython-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "documentation" + }, + "modules": [ + { + "file": "_thread/__init__.pyi", + "module": "__init__" + }, + { + "file": "array/__init__.pyi", + "module": "__init__" + }, + { + "file": "asyncio/__init__.pyi", + "module": "__init__" + }, + { + "file": "binascii/__init__.pyi", + "module": "__init__" + }, + { + "file": "bluetooth/__init__.pyi", + "module": "__init__" + }, + { + "file": "btree/__init__.pyi", + "module": "__init__" + }, + { + "file": "cmath/__init__.pyi", + "module": "__init__" + }, + { + "file": "collections/__init__.pyi", + "module": "__init__" + }, + { + "file": "cryptolib/__init__.pyi", + "module": "__init__" + }, + { + "file": "deflate/__init__.pyi", + "module": "__init__" + }, + { + "file": "errno/__init__.pyi", + "module": "__init__" + }, + { + "file": "esp/__init__.pyi", + "module": "__init__" + }, + { + "file": "esp32/__init__.pyi", + "module": "__init__" + }, + { + "file": "espnow/__init__.pyi", + "module": "__init__" + }, + { + "file": "framebuf/__init__.pyi", + "module": "__init__" + }, + { + "file": "gc/__init__.pyi", + "module": "__init__" + }, + { + "file": "gzip/__init__.pyi", + "module": "__init__" + }, + { + "file": "hashlib/__init__.pyi", + "module": "__init__" + }, + { + "file": "heapq/__init__.pyi", + "module": "__init__" + }, + { + "file": "io/__init__.pyi", + "module": "__init__" + }, + { + "file": "json/__init__.pyi", + "module": "__init__" + }, + { + "file": "lcd160cr/__init__.pyi", + "module": "__init__" + }, + { + "file": "machine/ADC.pyi", + "module": "ADC" + }, + { + "file": "machine/ADCBlock.pyi", + "module": "ADCBlock" + }, + { + "file": "machine/ADCWiPy.pyi", + "module": "ADCWiPy" + }, + { + "file": "machine/Counter.pyi", + "module": "Counter" + }, + { + "file": "machine/Encoder.pyi", + "module": "Encoder" + }, + { + "file": "machine/I2C.pyi", + "module": "I2C" + }, + { + "file": "machine/I2CTarget.pyi", + "module": "I2CTarget" + }, + { + "file": "machine/I2S.pyi", + "module": "I2S" + }, + { + "file": "machine/PWM.pyi", + "module": "PWM" + }, + { + "file": "machine/Pin.pyi", + "module": "Pin" + }, + { + "file": "machine/RTC.pyi", + "module": "RTC" + }, + { + "file": "machine/SD.pyi", + "module": "SD" + }, + { + "file": "machine/SDCard.pyi", + "module": "SDCard" + }, + { + "file": "machine/SPI.pyi", + "module": "SPI" + }, + { + "file": "machine/Signal.pyi", + "module": "Signal" + }, + { + "file": "machine/Timer.pyi", + "module": "Timer" + }, + { + "file": "machine/TimerWiPy.pyi", + "module": "TimerWiPy" + }, + { + "file": "machine/UART.pyi", + "module": "UART" + }, + { + "file": "machine/USBDevice.pyi", + "module": "USBDevice" + }, + { + "file": "machine/WDT.pyi", + "module": "WDT" + }, + { + "file": "machine/__init__.pyi", + "module": "__init__" + }, + { + "file": "marshal/__init__.pyi", + "module": "__init__" + }, + { + "file": "math/__init__.pyi", + "module": "__init__" + }, + { + "file": "micropython/__init__.pyi", + "module": "__init__" + }, + { + "file": "neopixel/__init__.pyi", + "module": "__init__" + }, + { + "file": "network/LAN.pyi", + "module": "LAN" + }, + { + "file": "network/PPP.pyi", + "module": "PPP" + }, + { + "file": "network/WIZNET5K.pyi", + "module": "WIZNET5K" + }, + { + "file": "network/WLAN.pyi", + "module": "WLAN" + }, + { + "file": "network/WLANWiPy.pyi", + "module": "WLANWiPy" + }, + { + "file": "network/__init__.pyi", + "module": "__init__" + }, + { + "file": "openamp/__init__.pyi", + "module": "__init__" + }, + { + "file": "os/__init__.pyi", + "module": "__init__" + }, + { + "file": "platform/__init__.pyi", + "module": "__init__" + }, + { + "file": "pyb/ADC.pyi", + "module": "ADC" + }, + { + "file": "pyb/Accel.pyi", + "module": "Accel" + }, + { + "file": "pyb/CAN.pyi", + "module": "CAN" + }, + { + "file": "pyb/DAC.pyi", + "module": "DAC" + }, + { + "file": "pyb/ExtInt.pyi", + "module": "ExtInt" + }, + { + "file": "pyb/Flash.pyi", + "module": "Flash" + }, + { + "file": "pyb/I2C.pyi", + "module": "I2C" + }, + { + "file": "pyb/LCD.pyi", + "module": "LCD" + }, + { + "file": "pyb/LED.pyi", + "module": "LED" + }, + { + "file": "pyb/Pin.pyi", + "module": "Pin" + }, + { + "file": "pyb/RTC.pyi", + "module": "RTC" + }, + { + "file": "pyb/SPI.pyi", + "module": "SPI" + }, + { + "file": "pyb/Servo.pyi", + "module": "Servo" + }, + { + "file": "pyb/Switch.pyi", + "module": "Switch" + }, + { + "file": "pyb/Timer.pyi", + "module": "Timer" + }, + { + "file": "pyb/UART.pyi", + "module": "UART" + }, + { + "file": "pyb/USB_HID.pyi", + "module": "USB_HID" + }, + { + "file": "pyb/USB_VCP.pyi", + "module": "USB_VCP" + }, + { + "file": "pyb/__init__.pyi", + "module": "__init__" + }, + { + "file": "random/__init__.pyi", + "module": "__init__" + }, + { + "file": "rp2/DMA.pyi", + "module": "DMA" + }, + { + "file": "rp2/Flash.pyi", + "module": "Flash" + }, + { + "file": "rp2/PIO.pyi", + "module": "PIO" + }, + { + "file": "rp2/StateMachine.pyi", + "module": "StateMachine" + }, + { + "file": "rp2/__init__.pyi", + "module": "__init__" + }, + { + "file": "select/__init__.pyi", + "module": "__init__" + }, + { + "file": "socket/__init__.pyi", + "module": "__init__" + }, + { + "file": "ssl/__init__.pyi", + "module": "__init__" + }, + { + "file": "stm/__init__.pyi", + "module": "__init__" + }, + { + "file": "struct/__init__.pyi", + "module": "__init__" + }, + { + "file": "sys/__init__.pyi", + "module": "__init__" + }, + { + "file": "time/__init__.pyi", + "module": "__init__" + }, + { + "file": "uarray.pyi", + "module": "uarray" + }, + { + "file": "uasyncio.pyi", + "module": "uasyncio" + }, + { + "file": "ubinascii.pyi", + "module": "ubinascii" + }, + { + "file": "ubluetooth.pyi", + "module": "ubluetooth" + }, + { + "file": "uctypes/__init__.pyi", + "module": "__init__" + }, + { + "file": "uerrno.pyi", + "module": "uerrno" + }, + { + "file": "uio.pyi", + "module": "uio" + }, + { + "file": "ujson.pyi", + "module": "ujson" + }, + { + "file": "umachine.pyi", + "module": "umachine" + }, + { + "file": "uos.pyi", + "module": "uos" + }, + { + "file": "uplatform.pyi", + "module": "uplatform" + }, + { + "file": "uselect.pyi", + "module": "uselect" + }, + { + "file": "usocket.pyi", + "module": "usocket" + }, + { + "file": "ussl.pyi", + "module": "ussl" + }, + { + "file": "ustruct.pyi", + "module": "ustruct" + }, + { + "file": "usys.pyi", + "module": "usys" + }, + { + "file": "utime.pyi", + "module": "utime" + }, + { + "file": "uzlib.pyi", + "module": "uzlib" + }, + { + "file": "vfs/__init__.pyi", + "module": "__init__" + }, + { + "file": "wipy/__init__.pyi", + "module": "__init__" + }, + { + "file": "wm8960/__init__.pyi", + "module": "__init__" + }, + { + "file": "zephyr/DiskAccess.pyi", + "module": "DiskAccess" + }, + { + "file": "zephyr/FlashArea.pyi", + "module": "FlashArea" + }, + { + "file": "zephyr/__init__.pyi", + "module": "__init__" + }, + { + "file": "zephyr/zsensor.pyi", + "module": "zsensor" + }, + { + "file": "zlib/__init__.pyi", + "module": "__init__" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ds18x20.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ds18x20.pyi new file mode 100644 index 000000000..cf3ac9fc2 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ds18x20.pyi @@ -0,0 +1,18 @@ +""" +Module: 'ds18x20' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def const(*args, **kwargs) -> Incomplete: ... + +class DS18X20: + def read_scratch(self, *args, **kwargs) -> Incomplete: ... + def read_temp(self, *args, **kwargs) -> Incomplete: ... + def write_scratch(self, *args, **kwargs) -> Incomplete: ... + def convert_temp(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/errno.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/errno.pyi new file mode 100644 index 000000000..0a736a827 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/errno.pyi @@ -0,0 +1,97 @@ +""" +System error codes. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/errno.html + +CPython module: :mod:`python:errno` https://docs.python.org/3/library/errno.html . + +This module provides access to symbolic error codes for `OSError` exception. +A particular inventory of codes depends on :term:`MicroPython port`. + +--- +Module: 'errno' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +ENOBUFS: Final[int] = 105 +"""No buffer space available""" +ENODEV: Final[int] = 19 +"""No such device""" +ENOENT: Final[int] = 2 +"""No such file or directory""" +EISDIR: Final[int] = 21 +"""Is a directory""" +EIO: Final[int] = 5 +"""I/O error""" +EINVAL: Final[int] = 22 +"""Invalid argument""" +EPERM: Final[int] = 1 +"""Operation not permitted""" +ETIMEDOUT: Final[int] = 116 +"""Connection timed out""" +ENOMEM: Final[int] = 12 +"""Out of memory""" +EOPNOTSUPP: Final[int] = 95 +"""Operation not supported""" +ENOTCONN: Final[int] = 128 +"""Transport endpoint is not connected""" +errorcode: dict = {} +"""\ +Dictionary mapping numeric error codes to strings with symbolic error +code (see above):: + +>>> print(errno.errorcode[errno.EEXIST]) +EEXIST +""" +EAGAIN: Final[int] = 11 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EALREADY: Final[int] = 120 +"""Operation already in progress""" +EBADF: Final[int] = 9 +"""Bad file descriptor""" +EADDRINUSE: Final[int] = 112 +"""Address already in use""" +EACCES: Final[int] = 13 +"""Permission denied""" +EINPROGRESS: Final[int] = 119 +"""Operation now in progress""" +EEXIST: Final[int] = 17 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EHOSTUNREACH: Final[int] = 118 +"""Host is unreachable""" +ECONNABORTED: Final[int] = 113 +"""Connection aborted""" +ECONNRESET: Final[int] = 104 +"""Connection reset by peer""" +ECONNREFUSED: Final[int] = 111 +"""Connection refused""" +ENOTSUP: Final[int] = ... +"""Operation not supported""" diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/firmware_stubs.json b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/firmware_stubs.json new file mode 100644 index 000000000..82be79336 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/firmware_stubs.json @@ -0,0 +1,80 @@ +{"firmware": {"variant": "", "build": "", "arch": "armv7emdp", "port": "mimxrt", "board": "SEEED_ARCH_MIX", "board_id": "SEEED_ARCH_MIX", "mpy": "v6.3", "ver": "1.26.1", "family": "micropython", "cpu": "MIMXRT1052DVL5B", "version": "1.26.1"}, +"stubber": {"version": "v1.26.3"}, "stubtype": "firmware", +"modules" :[ +{"module": "_asyncio", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_asyncio.pyi"}, +{"module": "_onewire", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_onewire.pyi"}, +{"module": "array", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/array.pyi"}, +{"module": "asyncio.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/__init__.pyi"}, +{"module": "asyncio.core", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/core.pyi"}, +{"module": "asyncio.event", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/event.pyi"}, +{"module": "asyncio.funcs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/funcs.pyi"}, +{"module": "asyncio.lock", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/lock.pyi"}, +{"module": "asyncio.stream", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/stream.pyi"}, +{"module": "binascii", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/binascii.pyi"}, +{"module": "builtins", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/builtins.pyi"}, +{"module": "cmath", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cmath.pyi"}, +{"module": "collections", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/collections.pyi"}, +{"module": "cryptolib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cryptolib.pyi"}, +{"module": "deflate", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/deflate.pyi"}, +{"module": "dht", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/dht.pyi"}, +{"module": "ds18x20", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ds18x20.pyi"}, +{"module": "errno", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/errno.pyi"}, +{"module": "framebuf", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/framebuf.pyi"}, +{"module": "gc", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/gc.pyi"}, +{"module": "hashlib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/hashlib.pyi"}, +{"module": "heapq", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/heapq.pyi"}, +{"module": "io", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/io.pyi"}, +{"module": "json", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/json.pyi"}, +{"module": "lwip", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/lwip.pyi"}, +{"module": "machine", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/machine.pyi"}, +{"module": "math", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/math.pyi"}, +{"module": "micropython", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/micropython.pyi"}, +{"module": "mimxrt", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mimxrt.pyi"}, +{"module": "mip", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip.pyi"}, +{"module": "mip.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip/__init__.pyi"}, +{"module": "network", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/network.pyi"}, +{"module": "ntptime", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ntptime.pyi"}, +{"module": "onewire", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/onewire.pyi"}, +{"module": "os", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/os.pyi"}, +{"module": "platform", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/platform.pyi"}, +{"module": "random", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/random.pyi"}, +{"module": "requests", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests.pyi"}, +{"module": "requests.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests/__init__.pyi"}, +{"module": "select", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/select.pyi"}, +{"module": "socket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/socket.pyi"}, +{"module": "ssl", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ssl.pyi"}, +{"module": "struct", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/struct.pyi"}, +{"module": "sys", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/sys.pyi"}, +{"module": "time", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/time.pyi"}, +{"module": "tls", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/tls.pyi"}, +{"module": "uarray", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uarray.pyi"}, +{"module": "uasyncio.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/__init__.pyi"}, +{"module": "uasyncio.core", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/core.pyi"}, +{"module": "uasyncio.event", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/event.pyi"}, +{"module": "uasyncio.funcs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/funcs.pyi"}, +{"module": "uasyncio.lock", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/lock.pyi"}, +{"module": "uasyncio.stream", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/stream.pyi"}, +{"module": "ubinascii", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ubinascii.pyi"}, +{"module": "ucollections", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucollections.pyi"}, +{"module": "ucryptolib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucryptolib.pyi"}, +{"module": "uctypes", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uctypes.pyi"}, +{"module": "uerrno", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uerrno.pyi"}, +{"module": "uhashlib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uhashlib.pyi"}, +{"module": "uheapq", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uheapq.pyi"}, +{"module": "uio", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uio.pyi"}, +{"module": "ujson", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ujson.pyi"}, +{"module": "umachine", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/umachine.pyi"}, +{"module": "uos", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uos.pyi"}, +{"module": "uplatform", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uplatform.pyi"}, +{"module": "urandom", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urandom.pyi"}, +{"module": "ure", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ure.pyi"}, +{"module": "urequests", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urequests.pyi"}, +{"module": "uselect", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uselect.pyi"}, +{"module": "usocket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usocket.pyi"}, +{"module": "ustruct", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ustruct.pyi"}, +{"module": "usys", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usys.pyi"}, +{"module": "utime", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/utime.pyi"}, +{"module": "uwebsocket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uwebsocket.pyi"}, +{"module": "vfs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/vfs.pyi"}, +{"module": "websocket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/websocket.pyi"} +]} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/framebuf.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/framebuf.pyi new file mode 100644 index 000000000..2f57ae0e7 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/framebuf.pyi @@ -0,0 +1,247 @@ +""" +Frame buffer manipulation. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/framebuf.html + +This module provides a general frame buffer which can be used to create +bitmap images, which can then be sent to a display. + +--- +Module: 'framebuf' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Optional, Union, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +MONO_HMSB: Final[int] = 4 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +MONO_HLSB: Final[int] = 3 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +RGB565: Final[int] = 1 +"""Red Green Blue (16-bit, 5+6+5) color format""" +MONO_VLSB: Final[int] = 0 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are vertically mapped with +bit 0 being nearest the top of the screen. Consequently each byte occupies +8 vertical pixels. Subsequent bytes appear at successive horizontal +locations until the rightmost edge is reached. Further bytes are rendered +at locations starting at the leftmost edge, 8 pixels lower. +""" +MVLSB: Final[int] = 0 +GS2_HMSB: Final[int] = 5 +"""Grayscale (2-bit) color format""" +GS8: Final[int] = 6 +"""Grayscale (8-bit) color format""" +GS4_HMSB: Final[int] = 2 +"""Grayscale (4-bit) color format""" + +def FrameBuffer1(*args, **kwargs) -> Incomplete: ... + +class FrameBuffer: + """ + The FrameBuffer class provides a pixel buffer which can be drawn upon with + pixels, lines, rectangles, text and even other FrameBuffer's. It is useful + when generating output for displays. + + For example:: + + import framebuf + + # FrameBuffer needs 2 bytes for every RGB565 pixel + fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565) + + fbuf.fill(0) + fbuf.text('MicroPython!', 0, 0, 0xffff) + fbuf.hline(0, 9, 96, 0xffff) + """ + def poly(self, x, y, coords, c, f: Union[bool, int] = False, /) -> Incomplete: + """ + Given a list of coordinates, draw an arbitrary (convex or concave) closed + polygon at the given x, y location using the given color. + + The *coords* must be specified as a :mod:`array` of integers, e.g. + ``array('h', [x0, y0, x1, y1, ... xn, yn])``. + + The optional *f* parameter can be set to ``True`` to fill the polygon. + Otherwise just a one pixel outline is drawn. + """ + ... + def vline(self, x: int, y: int, h: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + + @overload + def pixel(self, x: int, y: int, /) -> int: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + + @overload + def pixel(self, x: int, y: int, c: int, /) -> None: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + def text(self, s: str, x: int, y: int, c: int = 1, /) -> None: + """ + Write text to the FrameBuffer using the coordinates as the upper-left + corner of the text. The color of the text can be defined by the optional + argument but is otherwise a default value of 1. All characters have + dimensions of 8x8 pixels and there is currently no way to change the font. + """ + ... + def rect(self, x: int, y: int, w: int, h: int, c: int, f: Union[bool, int] = False, /) -> None: + """ + Draw a rectangle at the given location, size and color. + + The optional *f* parameter can be set to ``True`` to fill the rectangle. + Otherwise just a one pixel outline is drawn. + """ + ... + def scroll(self, xstep: int, ystep: int, /) -> None: + """ + Shift the contents of the FrameBuffer by the given vector. This may + leave a footprint of the previous colors in the FrameBuffer. + """ + ... + def ellipse(self, x, y, xr, yr, c, f: Union[bool, int] = False, m: Optional[int] = None) -> None: + """ + Draw an ellipse at the given location. Radii *xr* and *yr* define the + geometry; equal values cause a circle to be drawn. The *c* parameter + defines the color. + + The optional *f* parameter can be set to ``True`` to fill the ellipse. + Otherwise just a one pixel outline is drawn. + + The optional *m* parameter enables drawing to be restricted to certain + quadrants of the ellipse. The LS four bits determine which quadrants are + to be drawn, with bit 0 specifying Q1, b1 Q2, b2 Q3 and b3 Q4. Quadrants + are numbered counterclockwise with Q1 being top right. + """ + ... + def line(self, x1: int, y1: int, x2: int, y2: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def blit( + self, + fbuf: FrameBuffer, + x: int, + y: int, + key: int = -1, + palette: Optional[bytes] = None, + /, + ) -> None: + """ + Draw another FrameBuffer on top of the current one at the given coordinates. + If *key* is specified then it should be a color integer and the + corresponding color will be considered transparent: all pixels with that + color value will not be drawn. (If the *palette* is specified then the *key* + is compared to the value from *palette*, not to the value directly from + *fbuf*.) + + *fbuf* can be another FrameBuffer instance, or a tuple or list of the form:: + + (buffer, width, height, format) + + or:: + + (buffer, width, height, format, stride) + + This matches the signature of the FrameBuffer constructor, and the elements + of the tuple/list are the same as the arguments to the constructor except that + the *buffer* here can be read-only. + + The *palette* argument enables blitting between FrameBuffers with differing + formats. Typical usage is to render a monochrome or grayscale glyph/icon to + a color display. The *palette* is a FrameBuffer instance whose format is + that of the current FrameBuffer. The *palette* height is one pixel and its + pixel width is the number of colors in the source FrameBuffer. The *palette* + for an N-bit source needs 2**N pixels; the *palette* for a monochrome source + would have 2 pixels representing background and foreground colors. The + application assigns a color to each pixel in the *palette*. The color of the + current pixel will be that of that *palette* pixel whose x position is the + color of the corresponding source pixel. + """ + ... + def hline(self, x: int, y: int, w: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def fill(self, c: int, /) -> None: + """ + Fill the entire FrameBuffer with the specified color. + """ + ... + def fill_rect(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + buffer: AnyWritableBuf, + width: int, + height: int, + format: int, + stride: int = ..., + /, + ) -> None: + """ + Construct a FrameBuffer object. The parameters are: + + - *buffer* is an object with a buffer protocol which must be large + enough to contain every pixel defined by the width, height and + format of the FrameBuffer. + - *width* is the width of the FrameBuffer in pixels + - *height* is the height of the FrameBuffer in pixels + - *format* specifies the type of pixel used in the FrameBuffer; + permissible values are listed under Constants below. These set the + number of bits used to encode a color value and the layout of these + bits in *buffer*. + Where a color value c is passed to a method, c is a small integer + with an encoding that is dependent on the format of the FrameBuffer. + - *stride* is the number of pixels between each horizontal line + of pixels in the FrameBuffer. This defaults to *width* but may + need adjustments when implementing a FrameBuffer within another + larger FrameBuffer or screen. The *buffer* size must accommodate + an increased step size. + + One must specify valid *buffer*, *width*, *height*, *format* and + optionally *stride*. Invalid *buffer* size or dimensions may lead to + unexpected errors. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/gc.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/gc.pyi new file mode 100644 index 000000000..497082f3a --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/gc.pyi @@ -0,0 +1,112 @@ +""" +Control the garbage collector. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/gc.html + +CPython module: :mod:`python:gc` https://docs.python.org/3/library/gc.html . + +--- +Module: 'gc' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def mem_alloc() -> int: + """ + Return the number of bytes of heap RAM that are allocated by Python code. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +def isenabled(*args, **kwargs) -> Incomplete: ... +def mem_free() -> int: + """ + Return the number of bytes of heap RAM that is available for Python + code to allocate, or -1 if this amount is not known. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +@overload +def threshold() -> int: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +@overload +def threshold(amount: int) -> None: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +def collect() -> None: + """ + Run a garbage collection. + """ + ... + +def enable() -> None: + """ + Enable automatic garbage collection. + """ + ... + +def disable() -> None: + """ + Disable automatic garbage collection. Heap memory can still be allocated, + and garbage collection can still be initiated manually using :meth:`gc.collect`. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/hashlib.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/hashlib.pyi new file mode 100644 index 000000000..ef2d98ac0 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/hashlib.pyi @@ -0,0 +1,116 @@ +""" +Hashing algorithms. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/hashlib.html + +CPython module: :mod:`python:hashlib` https://docs.python.org/3/library/hashlib.html . + +This module implements binary data hashing algorithms. The exact inventory +of available algorithms depends on a board. Among the algorithms which may +be implemented: + +* SHA256 - The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + +* SHA1 - A previous generation algorithm. Not recommended for new usages, + but SHA1 is a part of number of Internet standards and existing + applications, so boards targeting network connectivity and + interoperability will try to provide this. + +* MD5 - A legacy algorithm, not considered cryptographically secure. Only + selected boards, targeting interoperability with legacy applications, + will offer this. + +--- +Module: 'hashlib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, _Hash +from typing import NoReturn, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated + +class sha1(_Hash): + """ + A previous generation algorithm. Not recommended for new usages, + but SHA1 is a part of number of Internet standards and existing + applications, so boards targeting network connectivity and + interoperability will try to provide this. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + +class sha256(_Hash): + """ + The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + +class md5(_Hash): + """ + A legacy algorithm, not considered cryptographically secure. Only + selected boards, targeting interoperability with legacy applications, + will offer this. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, data: AnyReadableBuf = ..., /) -> None: + """ + Create an MD5 hasher object and optionally feed ``data`` into it. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/heapq.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/heapq.pyi new file mode 100644 index 000000000..e861ff86b --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/heapq.pyi @@ -0,0 +1,46 @@ +""" +Heap queue algorithm. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/heapq.html + +CPython module: :mod:`python:heapq` https://docs.python.org/3/library/heapq.html . + +This module implements the +`min heap queue algorithm `_. + +A heap queue is essentially a list that has its elements stored in such a way +that the first item of the list is always the smallest. + +--- +Module: 'heapq' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +def heappop(heap: list[_T], /) -> _T: + """ + Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if + ``heap`` is empty. + + The returned item will be the smallest item in the ``heap``. + """ + ... + +def heappush(heap: list[_T], item: _T, /) -> None: + """ + Push the ``item`` onto the ``heap``. + """ + ... + +def heapify(x: list[Any], /) -> None: + """ + Convert the list ``x`` into a heap. This is an in-place operation. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/lwip.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/lwip.pyi new file mode 100644 index 000000000..74afeef79 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/lwip.pyi @@ -0,0 +1,51 @@ +""" +Module: 'lwip' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +SOCK_RAW: Final[int] = 3 +SOCK_STREAM: Final[int] = 1 +SOCK_DGRAM: Final[int] = 2 +MSG_PEEK: Final[int] = 1 +SO_REUSEADDR: Final[int] = 4 +SOL_SOCKET: Final[int] = 1 +SO_BROADCAST: Final[int] = 32 +TCP_NODELAY: Final[int] = 64 +AF_INET6: Final[int] = 10 +IPPROTO_IP: Final[int] = 0 +AF_INET: Final[int] = 2 +MSG_DONTWAIT: Final[int] = 2 +IP_DROP_MEMBERSHIP: Final[int] = 1025 +IPPROTO_TCP: Final[int] = 6 +IP_ADD_MEMBERSHIP: Final[int] = 1024 + +def reset(*args, **kwargs) -> Incomplete: ... +def print_pcbs(*args, **kwargs) -> Incomplete: ... +def getaddrinfo(*args, **kwargs) -> Incomplete: ... +def callback(*args, **kwargs) -> Incomplete: ... + +class socket: + def recvfrom(self, *args, **kwargs) -> Incomplete: ... + def recv(self, *args, **kwargs) -> Incomplete: ... + def makefile(self, *args, **kwargs) -> Incomplete: ... + def listen(self, *args, **kwargs) -> Incomplete: ... + def settimeout(self, *args, **kwargs) -> Incomplete: ... + def sendall(self, *args, **kwargs) -> Incomplete: ... + def setsockopt(self, *args, **kwargs) -> Incomplete: ... + def setblocking(self, *args, **kwargs) -> Incomplete: ... + def sendto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def connect(self, *args, **kwargs) -> Incomplete: ... + def send(self, *args, **kwargs) -> Incomplete: ... + def bind(self, *args, **kwargs) -> Incomplete: ... + def accept(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/machine.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/machine.pyi new file mode 100644 index 000000000..0baf2cdb9 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/machine.pyi @@ -0,0 +1,3251 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. + +--- +Module: 'machine' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import NoReturn, Union, List, Sequence, Optional, Callable, Tuple, overload, Any, Final +from _typeshed import Incomplete +from typing_extensions import deprecated, Awaitable, TypeAlias, TypeVar +from _mpy_shed import mp_available, _IRQ, AnyReadableBuf, AnyWritableBuf +from vfs import AbstractBlockDev + +SOFT_RESET: Final[int] = 5 +"""Reset causes.""" +PWRON_RESET: Final[int] = 1 +"""Reset causes.""" +WDT_RESET: Final[int] = 3 +"""Reset causes.""" +ID_T: TypeAlias = int | str +ATTN_0DB: int = ... +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +HARD_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +def unique_id() -> bytes: + """ + Returns a byte string with a unique identifier of a board/SoC. It will vary + from a board/SoC instance to another, if underlying hardware allows. Length + varies by hardware (so use substring of a full value if you expect a short + ID). In some MicroPython ports, ID corresponds to the network MAC address. + """ + ... + +def disable_irq() -> _IRQ_STATE: + """ + Disable interrupt requests. + Returns the previous IRQ state which should be considered an opaque value. + This return value should be passed to the `enable_irq()` function to restore + interrupts to their original state, before `disable_irq()` was called. + """ + ... + +def dht_readinto(*args, **kwargs) -> Incomplete: ... +def bitstream(pin, encoding, timing, data, /) -> Incomplete: + """ + Transmits *data* by bit-banging the specified *pin*. The *encoding* argument + specifies how the bits are encoded, and *timing* is an encoding-specific timing + specification. + + The supported encodings are: + + - ``0`` for "high low" pulse duration modulation. This will transmit 0 and + 1 bits as timed pulses, starting with the most significant bit. + The *timing* must be a four-tuple of nanoseconds in the format + ``(high_time_0, low_time_0, high_time_1, low_time_1)``. For example, + ``(400, 850, 800, 450)`` is the timing specification for WS2812 RGB LEDs + at 800kHz. + + The accuracy of the timing varies between ports. On Cortex M0 at 48MHz, it is + at best +/- 120ns, however on faster MCUs (ESP8266, ESP32, STM32, Pyboard), it + will be closer to +/-30ns. + + ``Note:`` For controlling WS2812 / NeoPixel strips, see the :mod:`neopixel` + module for a higher-level API. + """ + ... + +def bootloader(value: Optional[Any] = None) -> None: + """ + Reset the device and enter its bootloader. This is typically used to put the + device into a state where it can be programmed with new firmware. + + Some ports support passing in an optional *value* argument which can control + which bootloader to enter, what to pass to it, or other things. + """ + ... + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +def enable_irq(state: _IRQ_STATE, /) -> None: + """ + Re-enable interrupt requests. + The *state* parameter should be the value that was returned from the most + recent call to the `disable_irq()` function. + """ + ... + +def reset_cause() -> int: + """ + Get the reset cause. See :ref:`constants ` for the possible return values. + """ + ... + +def soft_reset() -> NoReturn: + """ + Performs a :ref:`soft reset ` of the interpreter, deleting all + Python objects and resetting the Python heap. + """ + ... + +def time_pulse_us(pin: Pin, pulse_level: int, timeout_us: int = 1_000_000, /) -> int: + """ + Time a pulse on the given *pin*, and return the duration of the pulse in + microseconds. The *pulse_level* argument should be 0 to time a low pulse + or 1 to time a high pulse. + + If the current input value of the pin is different to *pulse_level*, + the function first (*) waits until the pin input becomes equal to *pulse_level*, + then (**) times the duration that the pin is equal to *pulse_level*. + If the pin is already equal to *pulse_level* then timing starts straight away. + + The function will return -2 if there was timeout waiting for condition marked + (*) above, and -1 if there was timeout during the main measurement, marked (**) + above. The timeout is the same for both cases and given by *timeout_us* (which + is in microseconds). + """ + ... + +def reset() -> NoReturn: + """ + :ref:`Hard resets ` the device in a manner similar to pushing the + external RESET button. + """ + ... + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +def idle() -> None: + """ + Gates the clock to the CPU, useful to reduce power consumption at any time + during short or long periods. Peripherals continue working and execution + resumes as soon as any interrupt is triggered, or at most one millisecond + after the CPU was paused. + + It is recommended to call this function inside any tight loop that is + continuously checking for an external change (i.e. polling). This will reduce + power consumption without significantly impacting performance. To reduce + power consumption further then see the :func:`lightsleep`, + :func:`time.sleep()` and :func:`time.sleep_ms()` functions. + """ + ... + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +mem8: Incomplete ## = <8-bit memory> +"""Read/write 8 bits of memory.""" +mem32: Incomplete ## = <32-bit memory> +"""\ +Read/write 32 bits of memory. + +Use subscript notation ``[...]`` to index these objects with the address of +interest. Note that the address is the byte address, regardless of the size of +memory being accessed. + +Example use (registers are specific to an stm32 microcontroller): +""" +mem16: Incomplete ## = <16-bit memory> +"""Read/write 16 bits of memory.""" + +class LED: + def on(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class PWM: + """ + This class provides pulse width modulation output. + + Example usage:: + + from machine import PWM + + pwm = PWM(pin) # create a PWM object on a pin + pwm.duty_u16(32768) # set duty to 50% + + # reinitialise with a period of 200us, duty of 5us + pwm.init(freq=5000, duty_ns=5000) + + pwm.duty_ns(3000) # set pulse width to 3us + + pwm.deinit() + + + Limitations of PWM + ------------------ + + * Not all frequencies can be generated with absolute accuracy due to + the discrete nature of the computing hardware. Typically the PWM frequency + is obtained by dividing some integer base frequency by an integer divider. + For example, if the base frequency is 80MHz and the required PWM frequency is + 300kHz the divider must be a non-integer number 80000000 / 300000 = 266.67. + After rounding the divider is set to 267 and the PWM frequency will be + 80000000 / 267 = 299625.5 Hz, not 300kHz. If the divider is set to 266 then + the PWM frequency will be 80000000 / 266 = 300751.9 Hz, but again not 300kHz. + + * The duty cycle has the same discrete nature and its absolute accuracy is not + achievable. On most hardware platforms the duty will be applied at the next + frequency period. Therefore, you should wait more than "1/frequency" before + measuring the duty. + + * The frequency and the duty cycle resolution are usually interdependent. + The higher the PWM frequency the lower the duty resolution which is available, + and vice versa. For example, a 300kHz PWM frequency can have a duty cycle + resolution of 8 bit, not 16-bit as may be expected. In this case, the lowest + 8 bits of *duty_u16* are insignificant. So:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2) + + and:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255) + + will generate PWM with the same 50% duty cycle. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + def init(self, *, freq: int = ..., duty_u16: int = ..., duty_ns: int = ...) -> None: + """ + Modify settings for the PWM object. See the above constructor for details + about the parameters. + """ + ... + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + def deinit(self) -> None: + """ + Disable the PWM output. + """ + ... + def __init__( + self, + dest: PinLike, + /, + *, + freq: int = ..., + duty_u16: int = ..., + duty_ns: int = ..., + ) -> None: + """ + Construct and return a new PWM object using the following parameters: + + - *dest* is the entity on which the PWM is output, which is usually a + :ref:`machine.Pin ` object, but a port may allow other values, + like integers. + - *freq* should be an integer which sets the frequency in Hz for the + PWM cycle. + - *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``. + - *duty_ns* sets the pulse width in nanoseconds. + + Setting *freq* may affect other PWM objects if the objects share the same + underlying PWM generator (this is hardware specific). + Only one of *duty_u16* and *duty_ns* should be specified at a time. + """ + +class I2S: + """ + I2S is a synchronous serial protocol used to connect digital audio devices. + At the physical level, a bus consists of 3 lines: SCK, WS, SD. + The I2S class supports controller operation. Peripheral operation is not supported. + + The I2S class is currently available as a Technical Preview. During the preview period, feedback from + users is encouraged. Based on this feedback, the I2S class API and implementation may be changed. + + I2S objects can be created and initialized using:: + + from machine import I2S + from machine import Pin + + # ESP32 + sck_pin = Pin(14) # Serial clock output + ws_pin = Pin(13) # Word clock output + sd_pin = Pin(12) # Serial data output + + or + + # PyBoards + sck_pin = Pin("Y6") # Serial clock output + ws_pin = Pin("Y5") # Word clock output + sd_pin = Pin("Y8") # Serial data output + + audio_out = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.TX, + bits=16, + format=I2S.MONO, + rate=44100, + ibuf=20000) + + audio_in = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.RX, + bits=32, + format=I2S.STEREO, + rate=22050, + ibuf=20000) + + 3 modes of operation are supported: + - blocking + - non-blocking + - uasyncio + + blocking:: + + num_written = audio_out.write(buf) # blocks until buf emptied + + num_read = audio_in.readinto(buf) # blocks until buf filled + + non-blocking:: + + audio_out.irq(i2s_callback) # i2s_callback is called when buf is emptied + num_written = audio_out.write(buf) # returns immediately + + audio_in.irq(i2s_callback) # i2s_callback is called when buf is filled + num_read = audio_in.readinto(buf) # returns immediately + + uasyncio:: + + swriter = uasyncio.StreamWriter(audio_out) + swriter.write(buf) + await swriter.drain() + + sreader = uasyncio.StreamReader(audio_in) + num_read = await sreader.readinto(buf) + """ + + RX: Final[int] = 0 + """for initialising the I2S bus ``mode`` to receive""" + MONO: Final[int] = 0 + """for initialising the I2S bus ``format`` to mono""" + STEREO: Final[int] = 1 + """for initialising the I2S bus ``format`` to stereo""" + TX: Final[int] = 1 + """for initialising the I2S bus ``mode`` to transmit""" + @staticmethod + def shift( + buf: AnyWritableBuf, + bits: int, + shift: int, + /, + ) -> None: + """ + bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample. + Positive for left shift, negative for right shift. + Typically used for volume control. Each bit shift changes sample volume by 6dB. + """ + ... + def init( + self, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + see Constructor for argument descriptions + """ + ... + def irq( + self, + handler: Callable[[Any], None], + /, + ) -> None: + """ + Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method). + Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation. + ``handler`` is called in the context of the MicroPython scheduler. + """ + ... + def readinto( + self, + buf: AnyWritableBuf, + /, + ) -> int: + """ + Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the left channel sample data is used. + Returns number of bytes read + """ + ... + def deinit(self) -> None: + """ + Deinitialize the I2S bus + """ + ... + def write( + self, + buf: AnyReadableBuf, + /, + ) -> int: + """ + Write audio samples contained in ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the sample data is written to both the right and left channels. + Returns number of bytes written + """ + ... + def __init__( + self, + id: ID_T, + /, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + Construct an I2S object of the given id: + + - ``id`` identifies a particular I2S bus. + + ``id`` is board and port specific: + + - PYBv1.0/v1.1: has one I2S bus with id=2. + - PYBD-SFxW: has two I2S buses with id=1 and id=2. + - ESP32: has two I2S buses with id=0 and id=1. + + Keyword-only parameters that are supported on all ports: + + - ``sck`` is a pin object for the serial clock line + - ``ws`` is a pin object for the word select line + - ``sd`` is a pin object for the serial data line + - ``mode`` specifies receive or transmit + - ``bits`` specifies sample size (bits), 16 or 32 + - ``format`` specifies channel format, STEREO or MONO + - ``rate`` specifies audio sampling rate (samples/s) + - ``ibuf`` specifies internal buffer length (bytes) + + For all ports, DMA runs continuously in the background and allows user applications to perform other operations while + sample data is transfered between the internal buffer and the I2S peripheral unit. + Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations + before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method). + """ + +class ADC: + """ + The ADC class provides an interface to analog-to-digital convertors, and + represents a single endpoint that can sample a continuous voltage and + convert it to a discretised value. + + Example usage:: + + import machine + + adc = machine.ADC(pin) # create an ADC object acting on a pin + val = adc.read_u16() # read a raw analog value in the range 0-65535 + """ + + VREF: int = ... + CORE_VREF: int = ... + CORE_VBAT: int = ... + CORE_TEMP: int = ... + ATTN_0DB: int = 0 + ATTN_2_5DB: int = 1 + ATTN_6DB: int = 2 + ATTN_11DB: int = 3 + WIDTH_9BIT: int = 9 + WIDTH_10BIT: int = 10 + WIDTH_11BIT: int = 11 + WIDTH_12BIT: int = 12 + def read_uv(self) -> int: + """ + Take an analog reading and return an integer value with units of + microvolts. It is up to the particular port whether or not this value + is calibrated, and how calibration is done. + """ + ... + def read_u16(self) -> int: + """ + Take an analog reading and return an integer in the range 0-65535. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 65535. + """ + ... + def __init__(self, pin: PinLike, *, atten=ATTN_0DB) -> None: + """ + Access the ADC associated with a source identified by *id*. This + *id* may be an integer (usually specifying a channel number), a + :ref:`Pin ` object, or other value supported by the + underlying machine. + .. note:: + + WiPy has a custom implementation of ADC, see ADCWiPy for details. + + on ESP32 : `atten` specifies the attenuation level for the ADC input. + """ + + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class I2C: + """ + 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. + + I2C objects are created attached to a specific bus. They can be initialised + when created, or initialised later on. + + Printing the I2C object gives you information about its configuration. + + Both hardware and software I2C implementations exist via the + :ref:`machine.I2C ` and `machine.SoftI2C` classes. Hardware I2C uses + underlying hardware support of the system to perform the reads/writes and is + usually efficient and fast but may have restrictions on which pins can be used. + Software I2C is implemented by bit-banging and can be used on any pin but is not + as efficient. These classes have the same methods available and differ primarily + in the way they are constructed. + + Example usage:: + + from machine import I2C + + i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz + # depending on the port, extra parameters may be required + # to select the peripheral and/or pins to use + + i2c.scan() # scan for peripherals, returning a list of 7-bit addresses + + i2c.writeto(42, b'123') # write 3 bytes to peripheral with 7-bit address 42 + i2c.readfrom(42, 4) # read 4 bytes from peripheral with 7-bit address 42 + + i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of peripheral 42, + # starting at memory-address 8 in the peripheral + i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42 + # starting at address 2 in the peripheral + """ + def readfrom_mem_into(self, addr: int, memaddr: int, buf: AnyWritableBuf, /, *, addrsize: int = 8) -> None: + """ + Read into *buf* from the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. The number of bytes read is the + length of *buf*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def readfrom_into(self, addr: int, buf: AnyWritableBuf, stop: bool = True, /) -> None: + """ + Read into *buf* from the peripheral specified by *addr*. + The number of bytes read will be the length of *buf*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + + The method returns ``None``. + """ + ... + def readfrom_mem(self, addr: int, memaddr: int, nbytes: int, /, *, addrsize: int = 8) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr* starting from the memory + address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits. + Returns a `bytes` object with the data read. + """ + ... + def writeto_mem(self, addr: int, memaddr: int, buf: AnyReadableBuf, /, *, addrsize: int = 8) -> None: + """ + Write *buf* to the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def scan(self) -> List: + """ + 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 write bit) is sent on the bus. + """ + ... + def writeto(self, addr: int, buf: AnyReadableBuf, stop: bool = True, /) -> int: + """ + Write the bytes from *buf* to the peripheral specified by *addr*. If a + NACK is received following the write of a byte from *buf* then the + remaining bytes are not sent. If *stop* is true then a STOP condition is + generated at the end of the transfer, even if a NACK is received. + The function returns the number of ACKs that were received. + """ + ... + def writevto(self, addr: int, vector: Sequence[AnyReadableBuf], stop: bool = True, /) -> int: + """ + Write the bytes contained in *vector* to the peripheral specified by *addr*. + *vector* should be a tuple or list of objects with the buffer protocol. + The *addr* is sent once and then the bytes from each object in *vector* + are written out sequentially. The objects in *vector* may be zero bytes + in length in which case they don't contribute to the output. + + If a NACK is received following the write of a byte from one of the + objects in *vector* then the remaining bytes, and any remaining objects, + are not sent. If *stop* is true then a STOP condition is generated at + the end of the transfer, even if a NACK is received. The function + returns the number of ACKs that were received. + """ + ... + def start(self) -> None: + """ + Generate a START condition on the bus (SDA transitions to low while SCL is high). + """ + ... + def readfrom(self, addr: int, nbytes: int, stop: bool = True, /) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + Returns a `bytes` object with the data read. + """ + ... + def readinto(self, buf: AnyWritableBuf, nack: bool = True, /) -> None: + """ + Reads bytes from the bus and stores them into *buf*. The number of bytes + read is the length of *buf*. An ACK will be sent on the bus after + receiving all but the last byte. After the last byte is received, if *nack* + is true then a NACK will be sent, otherwise an ACK will be sent (and in this + case the peripheral assumes more bytes are going to be read in a later call). + """ + ... + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + def stop(self) -> None: + """ + Generate a STOP condition on the bus (SDA transitions to high while SCL is high). + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes from *buf* to the bus. Checks that an ACK is received + after each byte and stops transmitting the remaining bytes if a NACK is + received. The function returns the number of ACKs that were received. + """ + ... + + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class I2CTarget: + """ + Construct and return a new I2CTarget object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values depend on the + particular port/board. Some ports have a default in which case this parameter + can be omitted. + - *addr* is the I2C address of the target. + - *addrsize* is the number of bits in the I2C target address. Valid values + are 7 and 10. + - *mem* is an object with the buffer protocol that is writable. If not + specified then there is no backing memory and data must be read/written + using the :meth:`I2CTarget.readinto` and :meth:`I2CTarget.write` methods. + - *mem_addrsize* is the number of bits in the memory address. Valid values + are 0, 8, 16, 24 and 32. + - *scl* is a pin object specifying the pin to use for SCL. + - *sda* is a pin object specifying the pin to use for SDA. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + IRQ_END_READ: Final[int] = 16 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_WRITE: Final[int] = 2 + """IRQ trigger sources.""" + IRQ_END_WRITE: Final[int] = 32 + """IRQ trigger sources.""" + IRQ_READ_REQ: Final[int] = 4 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_READ: Final[int] = 1 + """IRQ trigger sources.""" + IRQ_WRITE_REQ: Final[int] = 8 + """IRQ trigger sources.""" + def deinit(self) -> Incomplete: + """ + Deinitialise the I2C target. After this method is called the hardware will no + longer respond to requests on the I2C bus, and no other methods can be called. + """ + ... + def irq(self, handler=None, trigger=IRQ_END_READ | IRQ_END_WRITE, hard=False) -> Incomplete: + """ + Configure an IRQ *handler* to be called when an event occurs. The possible events are + given by the following constants, which can be or'd together and passed to the *trigger* + argument: + + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a read transaction. + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a write transaction. + - ``IRQ_READ_REQ`` indicates that the controller is requesting data, and this + request must be satisfied by calling `I2CTarget.write` with the data to be + passed back to the controller. + - ``IRQ_WRITE_REQ`` indicates that the controller has written data, and the + data must be read by calling `I2CTarget.readinto`. + - ``IRQ_END_READ`` indicates that the controller has finished a read transaction. + - ``IRQ_END_WRITE`` indicates that the controller has finished a write transaction. + + Not all triggers are available on all ports. If a port has the constant then that + event is available. + + Note the following restrictions: + + - ``IRQ_ADDR_MATCH_READ``, ``IRQ_ADDR_MATCH_READ``, ``IRQ_READ_REQ`` and + ``IRQ_WRITE_REQ`` must be handled by a hard IRQ callback (with the *hard* argument + set to ``True``). This is because these events have very strict timing requirements + and must usually be satisfied synchronously with the hardware event. + + - ``IRQ_END_READ`` and ``IRQ_END_WRITE`` may be handled by either a soft or hard + IRQ callback (although note that all events must be registered with the same handler, + so if any events need a hard callback then all events must be hard). + + - If a memory buffer has been supplied in the constructor then ``IRQ_END_WRITE`` + is not emitted for the transaction that writes the memory address. This is to + allow ``IRQ_END_READ`` and ``IRQ_END_WRITE`` to function correctly as soft IRQ + callbacks, where the IRQ handler may be called quite some time after the actual + hardware event. + """ + ... + def write(self, buf) -> int: + """ + Write out the bytes from the given buffer, to be passed to the I2C controller + after it sends a read request. Returns the number of bytes written. Most ports + only accept one byte at a time to this method. + """ + ... + def readinto(self, buf) -> int: + """ + Read into the given buffer any pending bytes written by the I2C controller. + Returns the number of bytes read. + """ + ... + def __init__(self, id, addr, *, addrsize=7, mem=None, mem_addrsize=8, scl=None, sda=None) -> None: ... + +class UART: + """ + UART implements the standard UART/USART duplex serial communications protocol. At + the physical level it consists of 2 lines: RX and TX. The unit of communication + is a character (not to be confused with a string character) which can be 8 or 9 + bits wide. + + UART objects can be created and initialised using:: + + from machine import UART + + uart = UART(1, 9600) # init with given baudrate + uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters + + Supported parameters differ on a board: + + Pyboard: Bits can be 7, 8 or 9. Stop can be 1 or 2. With *parity=None*, + only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits + are supported. + + WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2. + + A UART object acts like a `stream` object and reading and writing is done + using the standard stream methods:: + + uart.read(10) # read 10 characters, returns a bytes object + uart.read() # read all available characters + uart.readline() # read a line + uart.readinto(buf) # read and store into the given buffer + uart.write('abc') # write the 3 characters + """ + + INV_TX: Final[int] = 1 + INV_RX: Final[int] = 2 + CTS: Final[int] = 2 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RXIDLE: Final[int] = 1 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + IRQ_TXIDLE: Final[int] = 2 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + RTS: Final[int] = 1 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RX: Incomplete + IRQ_BREAK: Incomplete + IDLE: int = ... + def irq( + self, + handler: Callable[[UART], None] | None = None, + trigger: int = 0, + hard: bool = False, + /, + ) -> _IRQ: + """ + Configure an interrupt handler to be called when a UART event occurs. + + The arguments are: + + - *handler* is an optional function to be called when the interrupt event + triggers. The handler must take exactly one argument which is the + ``UART`` instance. + + - *trigger* configures the event(s) which can generate an interrupt. + Possible values are a mask of one or more of the following: + + - ``UART.IRQ_RXIDLE`` interrupt after receiving at least one character + and then the RX line goes idle. + - ``UART.IRQ_RX`` interrupt after each received character. + - ``UART.IRQ_TXIDLE`` interrupt after or while the last character(s) of + a message are or have been sent. + - ``UART.IRQ_BREAK`` interrupt when a break state is detected at RX + + - *hard* if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + + Returns an irq object. + + Due to limitations of the hardware not all trigger events are available on all ports. + """ + ... + def sendbreak(self) -> None: + """ + Send a break condition on the bus. This drives the bus low for a duration + longer than required for a normal transmission of a character. + """ + ... + def deinit(self) -> None: + """ + Turn off the UART bus. + + .. note:: + You will not be able to call ``init()`` on the object after ``deinit()``. + A new instance needs to be created in that case. + """ + ... + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + def flush(self) -> Incomplete: + """ + Waits until all data has been sent. In case of a timeout, an exception is raised. The timeout + duration depends on the tx buffer size and the baud rate. Unless flow control is enabled, a timeout + should not occur. + + .. note:: + + For the esp8266 and nrf ports the call returns while the last byte is sent. + If required, a one character wait time has to be added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + def txdone(self) -> bool: + """ + Tells whether all data has been sent or no data transfer is happening. In this case, + it returns ``True``. If a data transmission is ongoing it returns ``False``. + + .. note:: + + For the esp8266 and nrf ports the call may return ``True`` even if the last byte + of a transfer is still being sent. If required, a one character wait time has to be + added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read without + blocking. It will return 0 if there are no characters available and a positive + number if there are characters. The method may return 1 even if there is more + than one character available for reading. + + For more sophisticated querying of available characters use select.poll:: + + poll = select.poll() + poll.register(uart, select.POLLIN) + poll.poll(timeout) + """ + ... + def write(self, buf: AnyReadableBuf, /) -> Union[int, None]: + """ + Write the buffer of bytes to the bus. + + Return value: number of bytes written or ``None`` on timeout. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + def readline(self) -> Union[str, None]: + """ + Read a line, ending in a newline character. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: the line read or ``None`` on timeout. + """ + ... + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + +class SoftI2C(I2C): + """ + Construct a new software I2C object. The parameters are: + + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + - *timeout* is the maximum time in microseconds to wait for clock + stretching (SCL held low by another device on the bus), after + which an ``OSError(ETIMEDOUT)`` exception is raised. + """ + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, scl, sda, *, freq=400000, timeout=50000) -> None: ... + +class SoftSPI(SPI): + """ + Construct a new software SPI object. Additional parameters must be + given, usually at least *sck*, *mosi* and *miso*, and these are used + to initialise the bus. See `SPI.init` for a description of the parameters. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + baudrate=500000, + *, + polarity=0, + phase=0, + bits=8, + firstbit=MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: ... + +class Timer: + """ + Hardware timers deal with timing of periods and events. Timers are perhaps + the most flexible and heterogeneous kind of hardware in MCUs and SoCs, + differently greatly from a model to a model. MicroPython's Timer class + defines a baseline operation of executing a callback with a given period + (or once after some delay), and allow specific boards to define more + non-standard behaviour (which thus won't be portable to other boards). + + See discussion of :ref:`important constraints ` on + Timer callbacks. + + .. note:: + + Memory can't be allocated inside irq handlers (an interrupt) and so + exceptions raised within a handler don't give much information. See + :func:`micropython.alloc_emergency_exception_buf` for how to get around this + limitation. + + If you are using a WiPy board please refer to :ref:`machine.TimerWiPy ` + instead of this class. + """ + + PERIODIC: Final[int] = 2 + """Timer operating mode.""" + ONE_SHOT: Final[int] = 1 + """Timer operating mode.""" + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + def deinit(self) -> None: + """ + Deinitialises the timer. Stops the timer, and disables the timer peripheral. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + +class WDT: + """ + The WDT 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 machine import WDT + wdt = WDT(timeout=2000) # enable it with a timeout of 2s + wdt.feed() + + Availability of this class: pyboard, WiPy, esp8266, esp32. + """ + def timeout_ms(self, *args, **kwargs) -> Incomplete: ... + def feed(self) -> None: + """ + Feed the WDT to prevent it from resetting the system. The application + should place this call in a sensible place ensuring that the WDT is + only fed after verifying that everything is functioning correctly. + """ + ... + def __init__(self, *, id: int = 0, timeout: int = 5000) -> None: + """ + Create a WDT object and start it. The timeout must be given in milliseconds. + Once it is running the timeout cannot be changed and the WDT cannot be stopped either. + + Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout + cannot be specified, it is determined by the underlying system. + """ + +class Pin: + """ + A pin object is used to control I/O pins (also known as GPIO - general-purpose + input/output). Pin objects are commonly associated with a physical pin that can + drive an output voltage and read input voltages. The pin class has methods to set the mode of + the pin (IN, OUT, etc) and methods to get and set the digital logic level. + For analog control of a pin, see the :class:`ADC` class. + + A pin object is constructed by using an identifier which unambiguously + specifies a certain I/O pin. The allowed forms of the identifier and the + physical pin that the identifier maps to are port-specific. Possibilities + for the identifier are an integer, a string or a tuple with port and pin + number. + + Usage Model:: + + from machine import Pin + + # create an output pin on pin #0 + p0 = Pin(0, Pin.OUT) + + # set the value low then high + p0.value(0) + p0.value(1) + + # create an input pin on pin #2, with a pull up resistor + p2 = Pin(2, Pin.IN, Pin.PULL_UP) + + # read and print the pin value + print(p2.value()) + + # reconfigure pin #0 in input mode with a pull down resistor + p0.init(p0.IN, p0.PULL_DOWN) + + # configure an irq callback + p0.irq(lambda p:print(p)) + """ + + OPEN_DRAIN: Final[int] = 2 + """Selects the pin mode.""" + IRQ_RISING: Final[int] = 1 + """Selects the IRQ trigger type.""" + IRQ_FALLING: Final[int] = 2 + """Selects the IRQ trigger type.""" + IN: Final[int] = 0 + """Selects the pin mode.""" + PULL_UP_22K: Final[int] = 3 + OUT: Final[int] = 1 + """Selects the pin mode.""" + PULL_UP: Final[int] = 2 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_HOLD: Final[int] = 5 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_DOWN: Final[int] = 0 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + DRIVE_2: Final[int] = 3 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_1: Final[int] = 2 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_0: Final[int] = 1 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + PULL_UP_47K: Final[int] = 1 + DRIVE_OFF: Final[int] = 0 + DRIVE_3: Final[int] = 4 + DRIVE_6: Final[int] = 7 + DRIVE_5: Final[int] = 6 + DRIVE_4: Final[int] = 5 + ALT: Incomplete + ALT_OPEN_DRAIN: Incomplete + ANALOG: Incomplete + IRQ_LOW_LEVEL: Incomplete + IRQ_HIGH_LEVEL: Incomplete + def low(self) -> None: + """ + Set pin to "0" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + def irq( + self, + /, + handler: Callable[[Pin], None] | None = None, + trigger: int = (IRQ_FALLING | IRQ_RISING), + *, + priority: int = 1, + wake: int | None = None, + hard: bool = False, + ) -> Callable[..., Incomplete]: + """ + Configure an interrupt handler to be called when the trigger source of the + pin is active. If the pin mode is ``Pin.IN`` then the trigger source is + the external value on the pin. If the pin mode is ``Pin.OUT`` then the + trigger source is the output buffer of the pin. Otherwise, if the pin mode + is ``Pin.OPEN_DRAIN`` then the trigger source is the output buffer for + state '0' and the external pin value for state '1'. + + The arguments are: + + - ``handler`` is an optional function to be called when the interrupt + triggers. The handler must take exactly one argument which is the + ``Pin`` instance. + + - ``trigger`` configures the event which can generate an interrupt. + Possible values are: + + - ``Pin.IRQ_FALLING`` interrupt on falling edge. + - ``Pin.IRQ_RISING`` interrupt on rising edge. + - ``Pin.IRQ_LOW_LEVEL`` interrupt on low level. + - ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level. + + These values can be OR'ed together to trigger on multiple events. + + - ``priority`` sets the priority level of the interrupt. The values it + can take are port-specific, but higher values always represent higher + priorities. + + - ``wake`` selects the power mode in which this interrupt can wake up the + system. It can be ``machine.IDLE``, ``machine.SLEEP`` or ``machine.DEEPSLEEP``. + These values can also be OR'ed together to make a pin generate interrupts in + more than one power mode. + + - ``hard`` if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + Not all ports support this argument. + + This method returns a callback object. + + The following methods are not part of the core Pin API and only implemented on certain ports. + """ + ... + def toggle(self) -> Incomplete: + """ + Toggle output pin from "0" to "1" or vice-versa. + + Availability: cc3200, esp32, esp8266, mimxrt, rp2, samd ports. + """ + ... + def off(self) -> None: + """ + Set pin to "0" output level. + """ + ... + def on(self) -> None: + """ + Set pin to "1" output level. + """ + ... + def init( + self, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Re-initialise the pin using the given parameters. Only those arguments that + are specified will be set. The rest of the pin peripheral state will remain + unchanged. See the constructor documentation for details of the arguments. + + Returns ``None``. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + def high(self) -> None: + """ + Set pin to "1" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + + class cpu: + GPIO_EMC_16: Pin ## = Pin(GPIO_EMC_16) + GPIO_EMC_15: Pin ## = Pin(GPIO_EMC_15) + GPIO_EMC_17: Pin ## = Pin(GPIO_EMC_17) + GPIO_EMC_18: Pin ## = Pin(GPIO_EMC_18) + GPIO_EMC_12: Pin ## = Pin(GPIO_EMC_12) + GPIO_EMC_14: Pin ## = Pin(GPIO_EMC_14) + GPIO_EMC_13: Pin ## = Pin(GPIO_EMC_13) + WAKEUP: Pin ## = Pin(WAKEUP) + GPIO_EMC_24: Pin ## = Pin(GPIO_EMC_24) + GPIO_EMC_23: Pin ## = Pin(GPIO_EMC_23) + GPIO_EMC_25: Pin ## = Pin(GPIO_EMC_25) + GPIO_EMC_19: Pin ## = Pin(GPIO_EMC_19) + GPIO_EMC_20: Pin ## = Pin(GPIO_EMC_20) + GPIO_EMC_22: Pin ## = Pin(GPIO_EMC_22) + GPIO_EMC_21: Pin ## = Pin(GPIO_EMC_21) + GPIO_EMC_01: Pin ## = Pin(GPIO_EMC_01) + GPIO_EMC_00: Pin ## = Pin(GPIO_EMC_00) + GPIO_EMC_02: Pin ## = Pin(GPIO_EMC_02) + GPIO_EMC_03: Pin ## = Pin(GPIO_EMC_03) + GPIO_B1_13: Pin ## = Pin(GPIO_B1_13) + GPIO_B1_15: Pin ## = Pin(GPIO_B1_15) + GPIO_B1_14: Pin ## = Pin(GPIO_B1_14) + GPIO_EMC_11: Pin ## = Pin(GPIO_EMC_11) + GPIO_EMC_09: Pin ## = Pin(GPIO_EMC_09) + GPIO_EMC_08: Pin ## = Pin(GPIO_EMC_08) + GPIO_EMC_10: Pin ## = Pin(GPIO_EMC_10) + GPIO_EMC_04: Pin ## = Pin(GPIO_EMC_04) + GPIO_EMC_05: Pin ## = Pin(GPIO_EMC_05) + GPIO_EMC_07: Pin ## = Pin(GPIO_EMC_07) + GPIO_EMC_06: Pin ## = Pin(GPIO_EMC_06) + GPIO_SD_B1_04: Pin ## = Pin(GPIO_SD_B1_04) + GPIO_SD_B1_03: Pin ## = Pin(GPIO_SD_B1_03) + GPIO_SD_B1_05: Pin ## = Pin(GPIO_SD_B1_05) + GPIO_SD_B1_06: Pin ## = Pin(GPIO_SD_B1_06) + GPIO_SD_B1_00: Pin ## = Pin(GPIO_SD_B1_00) + GPIO_SD_B1_02: Pin ## = Pin(GPIO_SD_B1_02) + GPIO_SD_B1_01: Pin ## = Pin(GPIO_SD_B1_01) + GPIO_EMC_26: Pin ## = Pin(GPIO_EMC_26) + PMIC_ON_REQ: Pin ## = Pin(PMIC_ON_REQ) + GPIO_SD_B1_11: Pin ## = Pin(GPIO_SD_B1_11) + PMIC_STBY_REQ: Pin ## = Pin(PMIC_STBY_REQ) + GPIO_SD_B1_07: Pin ## = Pin(GPIO_SD_B1_07) + GPIO_SD_B1_08: Pin ## = Pin(GPIO_SD_B1_08) + GPIO_SD_B1_10: Pin ## = Pin(GPIO_SD_B1_10) + GPIO_SD_B1_09: Pin ## = Pin(GPIO_SD_B1_09) + GPIO_EMC_31: Pin ## = Pin(GPIO_EMC_31) + GPIO_EMC_30: Pin ## = Pin(GPIO_EMC_30) + GPIO_EMC_32: Pin ## = Pin(GPIO_EMC_32) + GPIO_EMC_33: Pin ## = Pin(GPIO_EMC_33) + GPIO_EMC_27: Pin ## = Pin(GPIO_EMC_27) + GPIO_EMC_29: Pin ## = Pin(GPIO_EMC_29) + GPIO_EMC_28: Pin ## = Pin(GPIO_EMC_28) + GPIO_EMC_41: Pin ## = Pin(GPIO_EMC_41) + GPIO_EMC_39: Pin ## = Pin(GPIO_EMC_39) + GPIO_EMC_38: Pin ## = Pin(GPIO_EMC_38) + GPIO_EMC_40: Pin ## = Pin(GPIO_EMC_40) + GPIO_EMC_34: Pin ## = Pin(GPIO_EMC_34) + GPIO_EMC_35: Pin ## = Pin(GPIO_EMC_35) + GPIO_EMC_37: Pin ## = Pin(GPIO_EMC_37) + GPIO_EMC_36: Pin ## = Pin(GPIO_EMC_36) + GPIO_AD_B1_03: Pin ## = Pin(GPIO_AD_B1_03) + GPIO_AD_B1_02: Pin ## = Pin(GPIO_AD_B1_02) + GPIO_AD_B1_04: Pin ## = Pin(GPIO_AD_B1_04) + GPIO_AD_B1_05: Pin ## = Pin(GPIO_AD_B1_05) + GPIO_AD_B0_15: Pin ## = Pin(GPIO_AD_B0_15) + GPIO_AD_B1_01: Pin ## = Pin(GPIO_AD_B1_01) + GPIO_AD_B1_00: Pin ## = Pin(GPIO_AD_B1_00) + GPIO_B1_11: Pin ## = Pin(GPIO_B1_11) + GPIO_AD_B1_11: Pin ## = Pin(GPIO_AD_B1_11) + GPIO_AD_B1_10: Pin ## = Pin(GPIO_AD_B1_10) + GPIO_AD_B1_12: Pin ## = Pin(GPIO_AD_B1_12) + GPIO_AD_B1_06: Pin ## = Pin(GPIO_AD_B1_06) + GPIO_AD_B1_07: Pin ## = Pin(GPIO_AD_B1_07) + GPIO_AD_B1_09: Pin ## = Pin(GPIO_AD_B1_09) + GPIO_AD_B1_08: Pin ## = Pin(GPIO_AD_B1_08) + GPIO_AD_B0_04: Pin ## = Pin(GPIO_AD_B0_04) + GPIO_AD_B0_03: Pin ## = Pin(GPIO_AD_B0_03) + GPIO_AD_B0_05: Pin ## = Pin(GPIO_AD_B0_05) + GPIO_AD_B0_06: Pin ## = Pin(GPIO_AD_B0_06) + GPIO_AD_B0_00: Pin ## = Pin(GPIO_AD_B0_00) + GPIO_AD_B0_02: Pin ## = Pin(GPIO_AD_B0_02) + GPIO_AD_B0_01: Pin ## = Pin(GPIO_AD_B0_01) + GPIO_AD_B0_14: Pin ## = Pin(GPIO_AD_B0_14) + GPIO_AD_B0_12: Pin ## = Pin(GPIO_AD_B0_12) + GPIO_AD_B0_11: Pin ## = Pin(GPIO_AD_B0_11) + GPIO_AD_B0_13: Pin ## = Pin(GPIO_AD_B0_13) + GPIO_AD_B0_07: Pin ## = Pin(GPIO_AD_B0_07) + GPIO_AD_B0_08: Pin ## = Pin(GPIO_AD_B0_08) + GPIO_AD_B0_10: Pin ## = Pin(GPIO_AD_B0_10) + GPIO_AD_B0_09: Pin ## = Pin(GPIO_AD_B0_09) + GPIO_B1_01: Pin ## = Pin(GPIO_B1_01) + GPIO_B1_00: Pin ## = Pin(GPIO_B1_00) + GPIO_B1_02: Pin ## = Pin(GPIO_B1_02) + GPIO_B1_03: Pin ## = Pin(GPIO_B1_03) + GPIO_B0_13: Pin ## = Pin(GPIO_B0_13) + GPIO_B0_15: Pin ## = Pin(GPIO_B0_15) + GPIO_B0_14: Pin ## = Pin(GPIO_B0_14) + GPIO_AD_B1_13: Pin ## = Pin(GPIO_AD_B1_13) + GPIO_B1_09: Pin ## = Pin(GPIO_B1_09) + GPIO_B1_08: Pin ## = Pin(GPIO_B1_08) + GPIO_B1_10: Pin ## = Pin(GPIO_B1_10) + GPIO_B1_04: Pin ## = Pin(GPIO_B1_04) + GPIO_B1_05: Pin ## = Pin(GPIO_B1_05) + GPIO_B1_07: Pin ## = Pin(GPIO_B1_07) + GPIO_B1_06: Pin ## = Pin(GPIO_B1_06) + GPIO_B0_02: Pin ## = Pin(GPIO_B0_02) + GPIO_B0_01: Pin ## = Pin(GPIO_B0_01) + GPIO_B0_03: Pin ## = Pin(GPIO_B0_03) + GPIO_B0_04: Pin ## = Pin(GPIO_B0_04) + GPIO_AD_B1_14: Pin ## = Pin(GPIO_AD_B1_14) + GPIO_B0_00: Pin ## = Pin(GPIO_B0_00) + GPIO_AD_B1_15: Pin ## = Pin(GPIO_AD_B1_15) + GPIO_B0_12: Pin ## = Pin(GPIO_B0_12) + GPIO_B0_10: Pin ## = Pin(GPIO_B0_10) + GPIO_B0_09: Pin ## = Pin(GPIO_B0_09) + GPIO_B0_11: Pin ## = Pin(GPIO_B0_11) + GPIO_B0_05: Pin ## = Pin(GPIO_B0_05) + GPIO_B0_06: Pin ## = Pin(GPIO_B0_06) + GPIO_B0_08: Pin ## = Pin(GPIO_B0_08) + GPIO_B0_07: Pin ## = Pin(GPIO_B0_07) + def __init__(self, *argv, **kwargs) -> None: ... + + class board: + J5_22: Pin ## = Pin(GPIO_B0_15) + J5_25: Pin ## = Pin(GPIO_B1_02) + J5_24: Pin ## = Pin(GPIO_B1_01) + J5_23: Pin ## = Pin(GPIO_B1_00) + J5_26: Pin ## = Pin(GPIO_B1_03) + J5_30: Pin ## = Pin(GPIO_B0_03) + J5_29: Pin ## = Pin(GPIO_B0_02) + J5_28: Pin ## = Pin(GPIO_B0_01) + J5_06: Pin ## = Pin(GPIO_B0_06) + J5_17: Pin ## = Pin(GPIO_B0_14) + J5_12: Pin ## = Pin(GPIO_B0_09) + J5_08: Pin ## = Pin(GPIO_B0_08) + J5_07: Pin ## = Pin(GPIO_B0_07) + J5_13: Pin ## = Pin(GPIO_B0_10) + J5_16: Pin ## = Pin(GPIO_B0_13) + J5_15: Pin ## = Pin(GPIO_B0_12) + J5_14: Pin ## = Pin(GPIO_B0_11) + LED_GREEN: Pin ## = Pin(GPIO_AD_B0_10) + SCK_RX: Pin ## = Pin(GPIO_AD_B1_11) + MCK: Pin ## = Pin(GPIO_AD_B1_09) + LED_RED: Pin ## = Pin(GPIO_AD_B0_09) + SCK_TX: Pin ## = Pin(GPIO_AD_B1_14) + WS_RX: Pin ## = Pin(GPIO_AD_B1_10) + SD_TX: Pin ## = Pin(GPIO_AD_B1_13) + SD_RX: Pin ## = Pin(GPIO_AD_B1_12) + J5_32: Pin ## = Pin(GPIO_B0_00) + LED_BLUE: Pin ## = Pin(GPIO_AD_B0_11) + J5_36: Pin ## = Pin(GPIO_AD_B1_13) + J5_35: Pin ## = Pin(GPIO_AD_B1_14) + J5_34: Pin ## = Pin(GPIO_AD_B1_15) + J5_37: Pin ## = Pin(GPIO_AD_B1_12) + J5_50: Pin ## = Pin(GPIO_AD_B0_02) + J5_43: Pin ## = Pin(GPIO_AD_B1_01) + J5_42: Pin ## = Pin(GPIO_AD_B1_00) + WS_TX: Pin ## = Pin(GPIO_AD_B1_15) + J3_12: Pin ## = Pin(GPIO_B1_09) + J3_15: Pin ## = Pin(GPIO_AD_B0_15) + J3_14: Pin ## = Pin(GPIO_AD_B0_14) + J3_13: Pin ## = Pin(GPIO_B1_10) + J3_16: Pin ## = Pin(GPIO_AD_B1_00) + J3_20: Pin ## = Pin(GPIO_AD_B0_12) + J3_19: Pin ## = Pin(GPIO_AD_B0_13) + J3_17: Pin ## = Pin(GPIO_AD_B1_01) + J5_05: Pin ## = Pin(GPIO_B0_05) + J3_11: Pin ## = Pin(GPIO_B1_07) + J3_06: Pin ## = Pin(GPIO_EMC_41) + J3_05: Pin ## = Pin(GPIO_B1_06) + J3_04: Pin ## = Pin(GPIO_B1_11) + J3_07: Pin ## = Pin(GPIO_EMC_40) + J3_10: Pin ## = Pin(GPIO_B1_08) + J3_09: Pin ## = Pin(GPIO_B1_04) + J3_08: Pin ## = Pin(GPIO_B1_05) + J4_13: Pin ## = Pin(GPIO_AD_B1_13) + J4_16: Pin ## = Pin(GPIO_AD_B1_02) + J4_15: Pin ## = Pin(GPIO_AD_B1_15) + J4_14: Pin ## = Pin(GPIO_AD_B1_14) + J4_17: Pin ## = Pin(GPIO_AD_B1_03) + J5_04: Pin ## = Pin(GPIO_B0_04) + J4_20: Pin ## = Pin(GPIO_AD_B0_06) + J4_19: Pin ## = Pin(GPIO_AD_B0_07) + J4_04: Pin ## = Pin(GPIO_AD_B1_04) + J4_12: Pin ## = Pin(GPIO_AD_B1_12) + J4_07: Pin ## = Pin(GPIO_AD_B1_07) + J4_06: Pin ## = Pin(GPIO_AD_B1_06) + J4_05: Pin ## = Pin(GPIO_AD_B1_05) + J4_08: Pin ## = Pin(GPIO_AD_B1_08) + J4_11: Pin ## = Pin(GPIO_AD_B1_11) + J4_10: Pin ## = Pin(GPIO_AD_B1_10) + J4_09: Pin ## = Pin(GPIO_AD_B1_09) + def __init__(self, *argv, **kwargs) -> None: ... + + def __init__( + self, + id: Any, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Access the pin peripheral (GPIO pin) associated with the given ``id``. If + additional arguments are given in the constructor then they are used to initialise + the pin. Any settings that are not specified will remain in their previous state. + + The arguments are: + + - ``id`` is mandatory and can be an arbitrary object. Among possible value + types are: int (an internal Pin identifier), str (a Pin name), and tuple + (pair of [port, pin]). + + - ``mode`` specifies the pin mode, which can be one of: + + - ``Pin.IN`` - Pin is configured for input. If viewed as an output the pin + is in high-impedance state. + + - ``Pin.OUT`` - Pin is configured for (normal) output. + + - ``Pin.OPEN_DRAIN`` - Pin is configured for open-drain output. Open-drain + output works in the following way: if the output value is set to 0 the pin + is active at a low level; if the output value is 1 the pin is in a high-impedance + state. Not all ports implement this mode, or some might only on certain pins. + + - ``Pin.ALT`` - Pin is configured to perform an alternative function, which is + port specific. For a pin configured in such a way any other Pin methods + (except :meth:`Pin.init`) are not applicable (calling them will lead to undefined, + or a hardware-specific, result). Not all ports implement this mode. + + - ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as + open-drain. Not all ports implement this mode. + + - ``Pin.ANALOG`` - Pin is configured for analog input, see the :class:`ADC` class. + + - ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be + one of: + + - ``None`` - No pull up or down resistor. + - ``Pin.PULL_UP`` - Pull up resistor enabled. + - ``Pin.PULL_DOWN`` - Pull down resistor enabled. + + - ``value`` is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and specifies initial + output pin value if given, otherwise the state of the pin peripheral remains + unchanged. + + - ``drive`` specifies the output power of the pin and can be one of: ``Pin.LOW_POWER``, + ``Pin.MED_POWER`` or ``Pin.HIGH_POWER``. The actual current driving capabilities + are port dependent. Not all ports implement this argument. + + - ``alt`` specifies an alternate function for the pin and the values it can take are + port dependent. This argument is valid only for ``Pin.ALT`` and ``Pin.ALT_OPEN_DRAIN`` + modes. It may be used when a pin supports more than one alternate function. If only + one pin alternate function is supported the this argument is not required. Not all + ports implement this argument. + + As specified above, the Pin class allows to set an alternate function for a particular + pin, but it does not specify any further operations on such a pin. Pins configured in + alternate-function mode are usually not used as GPIO but are instead driven by other + hardware peripherals. The only operation supported on such a pin is re-initialising, + by calling the constructor or :meth:`Pin.init` method. If a pin that is configured in + alternate-function mode is re-initialised with ``Pin.IN``, ``Pin.OUT``, or + ``Pin.OPEN_DRAIN``, the alternate function will be removed from the pin. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class Signal(Pin): + """ + The Signal class is a simple extension of the `Pin` class. Unlike Pin, which + can be only in "absolute" 0 and 1 states, a Signal can be in "asserted" + (on) or "deasserted" (off) states, while being inverted (active-low) or + not. In other words, it adds logical inversion support to Pin functionality. + While this may seem a simple addition, it is exactly what is needed to + support wide array of simple digital devices in a way portable across + different boards, which is one of the major MicroPython goals. Regardless + of whether different users have an active-high or active-low LED, a normally + open or normally closed relay - you can develop a single, nicely looking + application which works with each of them, and capture hardware + configuration differences in few lines in the config file of your app. + + Example:: + + from machine import Pin, Signal + + # Suppose you have an active-high LED on pin 0 + led1_pin = Pin(0, Pin.OUT) + # ... and active-low LED on pin 1 + led2_pin = Pin(1, Pin.OUT) + + # Now to light up both of them using Pin class, you'll need to set + # them to different values + led1_pin.value(1) + led2_pin.value(0) + + # Signal class allows to abstract away active-high/active-low + # difference + led1 = Signal(led1_pin, invert=False) + led2 = Signal(led2_pin, invert=True) + + # Now lighting up them looks the same + led1.value(1) + led2.value(1) + + # Even better: + led1.on() + led2.on() + + Following is the guide when Signal vs Pin should be used: + + * Use Signal: If you want to control a simple on/off (including software + PWM!) devices like LEDs, multi-segment indicators, relays, buzzers, or + read simple binary sensors, like normally open or normally closed buttons, + pulled high or low, Reed switches, moisture/flame detectors, etc. etc. + Summing up, if you have a real physical device/sensor requiring GPIO + access, you likely should use a Signal. + + * Use Pin: If you implement a higher-level protocol or bus to communicate + with more complex devices. + + The split between Pin and Signal come from the use cases above and the + architecture of MicroPython: Pin offers the lowest overhead, which may + be important when bit-banging protocols. But Signal adds additional + flexibility on top of Pin, at the cost of minor overhead (much smaller + than if you implemented active-high vs active-low device differences in + Python manually!). Also, Pin is a low-level object which needs to be + implemented for each support board, while Signal is a high-level object + which comes for free once Pin is implemented. + + If in doubt, give the Signal a try! Once again, it is offered to save + developers from the need to handle unexciting differences like active-low + vs active-high signals, and allow other users to share and enjoy your + application, instead of being frustrated by the fact that it doesn't + work for them simply because their LEDs or relays are wired in a slightly + different way. + """ + def off(self) -> None: + """ + Deactivate signal. + """ + ... + def on(self) -> None: + """ + Activate signal. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + +class RTC: + """ + The RTC is an independent clock that keeps track of the date + and time. + + Example usage:: + + rtc = machine.RTC() + rtc.datetime((2020, 1, 21, 2, 10, 32, 36, 0)) + print(rtc.datetime()) + + + + The documentation for RTC is in a poor state;1 + """ + + ALARM0: Final[int] = 0 + """irq trigger source""" + def irq( + self, + /, + *, + trigger: int, + handler: Callable[[RTC], None] | None = None, + wake: int = IDLE, + ) -> None: + """ + Create an irq object triggered by a real time clock alarm. + + - ``trigger`` must be ``RTC.ALARM0`` + - ``handler`` is the function to be called when the callback is triggered. + - ``wake`` specifies the sleep mode from where this interrupt can wake + up the system. + """ + ... + def cancel(self, *args, **kwargs) -> Incomplete: ... + def datetime(self, datetimetuple: Any | None = None) -> Tuple: + """ + Get or set the date and time of the RTC. + + With no arguments, this method returns an 8-tuple with the current + date and time. With 1 argument (being an 8-tuple) it sets the date + and time. + + The 8-tuple has the following format: + + (year, month, day, weekday, hours, minutes, seconds, subseconds) + + The meaning of the ``subseconds`` field is hardware dependent. + """ + ... + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + def calibration(self, *args, **kwargs) -> Incomplete: ... + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + def alarm_cancel(self, alarm_id: int = 0, /) -> None: + """ + Cancel a running alarm. + + The mimxrt port also exposes this function as ``RTC.cancel(alarm_id=0)``, but this is + scheduled to be removed in MicroPython 2.0. + """ + ... + def alarm_left(self, alarm_id: int = 0, /) -> int: + """ + Get the number of milliseconds left before the alarm expires. + """ + ... + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + +class SDCard(AbstractBlockDev): + """ + SD cards are one of the most common small form factor removable storage media. + SD cards come in a variety of sizes and physical form factors. MMC cards are + similar removable storage devices while eMMC devices are electrically similar + storage devices designed to be embedded into other systems. All three form + share a common protocol for communication with their host system and high-level + support looks the same for them all. As such in MicroPython they are implemented + in a single class called :class:`machine.SDCard` . + + Both SD and MMC interfaces support being accessed with a variety of bus widths. + When being accessed with a 1-bit wide interface they can be accessed using the + SPI protocol. Different MicroPython hardware platforms support different widths + and pin configurations but for most platforms there is a standard configuration + for any given hardware. In general constructing an ``SDCard`` object with without + passing any parameters will initialise the interface to the default card slot + for the current hardware. The arguments listed below represent the common + arguments that might need to be set in order to use either a non-standard slot + or a non-standard pin assignment. The exact subset of arguments supported will + vary from platform to platform. + + + Implementation-specific details + ------------------------------- + + Different implementations of the ``SDCard`` class on different hardware support + varying subsets of the options above. + + PyBoard + ``````` + + The standard PyBoard has just one slot. No arguments are necessary or supported. + + ESP32 + ````` + + The ESP32 provides two channels of SD/MMC hardware and also supports + access to SD Cards through either of the two SPI ports that are + generally available to the user. As a result the *slot* argument can + take a value between 0 and 3, inclusive. Slots 0 and 1 use the + built-in SD/MMC hardware while slots 2 and 3 use the SPI ports. Slot 0 + supports 1, 4 or 8-bit wide access while slot 1 supports 1 or 4-bit + access; the SPI slots only support 1-bit access. + + .. note:: Slot 0 is used to communicate with on-board flash memory + on most ESP32 modules and so will be unavailable to the + user. + + .. note:: Most ESP32 modules that provide an SD card slot using the + dedicated hardware only wire up 1 data pin, so the default + value for *width* is 1. + + The pins used by the dedicated SD/MMC hardware are fixed. The pins + used by the SPI hardware can be reassigned. + + .. note:: If any of the SPI signals are remapped then all of the SPI + signals will pass through a GPIO multiplexer unit which + can limit the performance of high frequency signals. Since + the normal operating speed for SD cards is 40MHz this can + cause problems on some cards. + + The default (and preferred) pin assignment are as follows: + + ====== ====== ====== ====== ====== + Slot 0 1 2 3 + ------ ------ ------ ------ ------ + Signal Pin Pin Pin Pin + ====== ====== ====== ====== ====== + sck 6 14 18 14 + cmd 11 15 + cs 5 15 + miso 19 12 + mosi 23 13 + D0 7 2 + D1 8 4 + D2 9 12 + D3 10 13 + D4 16 + D5 17 + D6 5 + D7 18 + ====== ====== ====== ====== ====== + + cc3200 + `````` + + You can set the pins used for SPI access by passing a tuple as the + *pins* argument. + + *Note:* The current cc3200 SD card implementation names the this class + :class:`machine.SD` rather than :class:`machine.SDCard` . + """ + def present(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def info(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SPI: + """ + SPI is a synchronous serial protocol that is driven by a controller. At the + physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices + can share the same bus. Each device should have a separate, 4th signal, + CS (Chip Select), to select a particular device on a bus with which + communication takes place. Management of a CS signal should happen in + user code (via machine.Pin class). + + Both hardware and software SPI implementations exist via the + :ref:`machine.SPI ` and `machine.SoftSPI` classes. Hardware SPI uses underlying + hardware support of the system to perform the reads/writes and is usually + efficient and fast but may have restrictions on which pins can be used. + Software SPI is implemented by bit-banging and can be used on any pin but + is not as efficient. These classes have the same methods available and + differ primarily in the way they are constructed. + + Example usage:: + + from machine import SPI, Pin + + spi = SPI(0, baudrate=400000) # Create SPI peripheral 0 at frequency of 400kHz. + # Depending on the use case, extra parameters may be required + # to select the bus characteristics and/or pins to use. + cs = Pin(4, mode=Pin.OUT, value=1) # Create chip-select on pin 4. + + try: + cs(0) # Select peripheral. + spi.write(b"12345678") # Write 8 bytes, and don't care about received data. + finally: + cs(1) # Deselect peripheral. + + try: + cs(0) # Select peripheral. + rxdata = spi.read(8, 0x42) # Read 8 bytes while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + rxdata = bytearray(8) + try: + cs(0) # Select peripheral. + spi.readinto(rxdata, 0x42) # Read 8 bytes inplace while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + txdata = b"12345678" + rxdata = bytearray(len(txdata)) + try: + cs(0) # Select peripheral. + spi.write_readinto(txdata, rxdata) # Simultaneously write and read bytes. + finally: + cs(1) # Deselect peripheral. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + CONTROLLER: Incomplete + def deinit(self) -> None: + """ + Turn off the SPI bus. + """ + ... + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + def write_readinto(self, write_buf: AnyReadableBuf, read_buf: AnyWritableBuf, /) -> int: + """ + Write the bytes from ``write_buf`` while reading into ``read_buf``. The + buffers can be the same or different, but both buffers must have the + same length. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def read(self, nbytes: int, write: int = 0x00, /) -> bytes: + """ + Read a number of bytes specified by ``nbytes`` while continuously writing + the single byte given by ``write``. + Returns a ``bytes`` object with the data that was read. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes contained in ``buf``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def readinto(self, buf: AnyWritableBuf, write: int = 0x00, /) -> int: + """ + Read into the buffer specified by ``buf`` while continuously writing the + single byte given by ``write``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes read. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/math.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/math.pyi new file mode 100644 index 000000000..dcc5cea90 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/math.pyi @@ -0,0 +1,269 @@ +""" +Mathematical functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/math.html + +CPython module: :mod:`python:math` https://docs.python.org/3/library/math.html . + +The ``math`` module provides some basic mathematical functions for +working with floating-point numbers. + +*Note:* On the pyboard, floating-point numbers have 32-bit precision. + +Availability: not available on WiPy. Floating point support required +for this module. + +--- +Module: 'math' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsFloat, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +inf: float = inf +nan: float = nan +pi: float = 3.141592653589793 +"""the ratio of a circle's circumference to its diameter""" +e: float = 2.718281828459045 +"""base of the natural logarithm""" +tau: float = 6.283185307179586 + +def ldexp(x: SupportsFloat, exp: int, /) -> float: + """ + Return ``x * (2**exp)``. + """ + ... + +def lgamma(x: SupportsFloat, /) -> float: + """ + Return the natural logarithm of the gamma function of ``x``. + """ + ... + +def trunc(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards 0. + """ + ... + +def isclose(*args, **kwargs) -> Incomplete: ... +def gamma(x: SupportsFloat, /) -> float: + """ + Return the gamma function of ``x``. + """ + ... + +def isnan(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is not-a-number + """ + ... + +def isfinite(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is finite. + """ + ... + +def isinf(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is infinite. + """ + ... + +def sqrt(x: SupportsFloat, /) -> float: + """ + Return the square root of ``x``. + """ + ... + +def sinh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic sine of ``x``. + """ + ... + +def log(x: SupportsFloat, /) -> float: + """ + With one argument, return the natural logarithm of *x*. + + With two arguments, return the logarithm of *x* to the given *base*. + """ + ... + +def tan(x: SupportsFloat, /) -> float: + """ + Return the tangent of ``x``. + """ + ... + +def tanh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic tangent of ``x``. + """ + ... + +def log2(x: SupportsFloat, /) -> float: + """ + Return the base-2 logarithm of ``x``. + """ + ... + +def log10(x: SupportsFloat, /) -> float: + """ + Return the base-10 logarithm of ``x``. + """ + ... + +def sin(x: SupportsFloat, /) -> float: + """ + Return the sine of ``x``. + """ + ... + +def modf(x: SupportsFloat, /) -> Tuple: + """ + Return a tuple of two floats, being the fractional and integral parts of + ``x``. Both return values have the same sign as ``x``. + """ + ... + +def radians(x: SupportsFloat, /) -> float: + """ + Return degrees ``x`` converted to radians. + """ + ... + +def atanh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic tangent of ``x``. + """ + ... + +def atan2(y: SupportsFloat, x: SupportsFloat, /) -> float: + """ + Return the principal value of the inverse tangent of ``y/x``. + """ + ... + +def atan(x: SupportsFloat, /) -> float: + """ + Return the inverse tangent of ``x``. + """ + ... + +def ceil(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards positive infinity. + """ + ... + +def copysign(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return ``x`` with the sign of ``y``. + """ + ... + +def frexp(x: SupportsFloat, /) -> tuple[float, 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 acos(x: SupportsFloat, /) -> float: + """ + Return the inverse cosine of ``x``. + """ + ... + +def pow(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Returns ``x`` to the power of ``y``. + """ + ... + +def asinh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic sine of ``x``. + """ + ... + +def acosh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic cosine of ``x``. + """ + ... + +def asin(x: SupportsFloat, /) -> float: + """ + Return the inverse sine of ``x``. + """ + ... + +def factorial(*args, **kwargs) -> Incomplete: ... +def fabs(x: SupportsFloat, /) -> float: + """ + Return the absolute value of ``x``. + """ + ... + +def expm1(x: SupportsFloat, /) -> float: + """ + Return ``exp(x) - 1``. + """ + ... + +def floor(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards negative infinity. + """ + ... + +def fmod(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return the remainder of ``x/y``. + """ + ... + +def cos(x: SupportsFloat, /) -> float: + """ + Return the cosine of ``x``. + """ + ... + +def degrees(x: SupportsFloat, /) -> float: + """ + Return radians ``x`` converted to degrees. + """ + ... + +def cosh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic cosine of ``x``. + """ + ... + +def exp(x: SupportsFloat, /) -> float: + """ + Return the exponential of ``x``. + """ + ... + +def erf(x: SupportsFloat, /) -> float: + """ + Return the error function of ``x``. + """ + ... + +def erfc(x: SupportsFloat, /) -> float: + """ + Return the complementary error function of ``x``. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/micropython.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/micropython.pyi new file mode 100644 index 000000000..42982aee2 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/micropython.pyi @@ -0,0 +1,346 @@ +""" +Access and control MicroPython internals. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/micropython.html + +--- +Module: 'micropython' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Any, Callable, Optional, Tuple, overload +from typing_extensions import Awaitable, ParamSpec, TypeAlias, TypeVar + +_T = TypeVar("_T") +_F = TypeVar("_F", bound=Callable[..., Any]) +Const_T = TypeVar("Const_T", int, float, str, bytes, Tuple) +_Param = ParamSpec("_Param") +_Ret = TypeVar("_Ret") + +@overload +def opt_level() -> int: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def opt_level(level: int, /) -> None: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def mem_info() -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +@overload +def mem_info(verbose: Any, /) -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +def kbd_intr(chr: int) -> None: + """ + Set the character that will raise a `KeyboardInterrupt` exception. By + default this is set to 3 during script execution, corresponding to Ctrl-C. + Passing -1 to this function will disable capture of Ctrl-C, and passing 3 + will restore it. + + This function can be used to prevent the capturing of Ctrl-C on the + incoming stream of characters that is usually used for the REPL, in case + that stream is used for other purposes. + """ + ... + +@overload +def qstr_info() -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +@overload +def qstr_info(verbose: bool, /) -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +def schedule(func: Callable[[_T], None], arg: _T, /) -> None: + """ + Schedule the function *func* to be executed "very soon". The function + is passed the value *arg* as its single argument. "Very soon" means that + the MicroPython runtime will do its best to execute the function at the + earliest possible time, given that it is also trying to be efficient, and + that the following conditions hold: + + - A scheduled function will never preempt another scheduled function. + - Scheduled functions are always executed "between opcodes" which means + that all fundamental Python operations (such as appending to a list) + are guaranteed to be atomic. + - A given port may define "critical regions" within which scheduled + functions will never be executed. Functions may be scheduled within + a critical region but they will not be executed until that region + is exited. An example of a critical region is a preempting interrupt + handler (an IRQ). + + A use for this function is to schedule a callback from a preempting IRQ. + Such an IRQ puts restrictions on the code that runs in the IRQ (for example + the heap may be locked) and scheduling a function to call later will lift + those restrictions. + + On multi-threaded ports, the scheduled function's behaviour depends on + whether the Global Interpreter Lock (GIL) is enabled for the specific port: + + - If GIL is enabled, the function can preempt any thread and run in its + context. + - If GIL is disabled, the function will only preempt the main thread and run + in its context. + + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite queue to hold the scheduled functions and `schedule()` + will raise a `RuntimeError` if the queue is full. + """ + ... + +def stack_use() -> int: + """ + Return an integer representing the current amount of stack that is being + used. The absolute value of this is not particularly useful, rather it + should be used to compute differences in stack usage at different points. + """ + ... + +def heap_unlock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def const(expr: Const_T, /) -> Const_T: + """ + Used to declare that the expression is a constant so that the compiler can + optimise it. The use of this function should be as follows:: + + from micropython import const + + CONST_X = const(123) + CONST_Y = const(2 * CONST_X + 1) + + Constants declared this way are still accessible as global variables from + outside the module they are declared in. On the other hand, if a constant + begins with an underscore then it is hidden, it is not available as a global + variable, and does not take up any memory during execution. + + This `const` function is recognised directly by the MicroPython parser and is + provided as part of the :mod:`micropython` module mainly so that scripts can be + written which run under both CPython and MicroPython, by following the above + pattern. + """ + ... + +def heap_lock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def alloc_emergency_exception_buf(size: int, /) -> None: + """ + Allocate *size* bytes of RAM for the emergency exception buffer (a good + size is around 100 bytes). The buffer is used to create exceptions in cases + when normal RAM allocation would fail (eg within an interrupt handler) and + therefore give useful traceback information in these situations. + + A good way to use this function is to put it at the start of your main script + (eg ``boot.py`` or ``main.py``) and then the emergency exception buffer will be active + for all the code following it. + """ + ... + +class RingIO: + def readinto(self, buf, nbytes: Optional[Any] = None) -> int: + """ + Read available bytes into the provided ``buf``. If ``nbytes`` is + specified then read at most that many bytes. Otherwise, read at + most ``len(buf)`` bytes. + + Return value: Integer count of the number of bytes read into ``buf``. + """ + ... + def write(self, buf) -> int: + """ + Non-blocking write of bytes from ``buf`` into the ringbuffer, limited + by the available space in the ringbuffer. + + Return value: Integer count of bytes written. + """ + ... + def readline(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read a line, ending in a newline character or return if one exists in + the buffer, else return available bytes in buffer. If ``nbytes`` is + specified then read at most that many bytes. + + Return value: a bytes object containing the line read. + """ + ... + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read. + """ + ... + def read(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read available characters. This is a non-blocking function. If ``nbytes`` + is specified then read at most that many bytes, otherwise read as much + data as possible. + + Return value: a bytes object containing the bytes read. Will be + zero-length bytes object if no data is available. + """ + ... + def close(self) -> Incomplete: + """ + No-op provided as part of standard `stream` interface. Has no effect + on data in the ringbuffer. + """ + ... + def __init__(self, size) -> None: ... + +# decorators +@mp_available() # force merge +def viper(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + The Viper code emitter is not fully compliant. It supports special Viper native data types in pursuit of performance. + Integer processing is non-compliant because it uses machine words: arithmetic on 32 bit hardware is performed modulo 2**32. + Like the Native emitter Viper produces machine instructions but further optimisations are performed, substantially increasing + performance especially for integer arithmetic and bit manipulations. + See: https://docs.micropython.org/en/latest/reference/speed_python.html?highlight=viper#the-native-code-emitter + """ + ... + +@mp_available() # force merge +def native(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This causes the MicroPython compiler to emit native CPU opcodes rather than bytecode. + It covers the bulk of the MicroPython functionality, so most functions will require no adaptation. + See: https://docs.micropython.org/en/latest/reference/speed_python.html#the-native-code-emitter + """ + ... + +@mp_available(macro="MICROPY_EMIT_INLINE_THUMB") # force merge +def asm_thumb(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code. + The assembler code is written is a subset of the ARM Thumb-2 instruction set, and is executed on the target CPU. + + Availability: Only on specific boards where MICROPY_EMIT_INLINE_THUMB is defined. + See: https://docs.micropython.org/en/latest/reference/asm_thumb2_index.html + """ + ... + +@mp_available(port="esp8266") # force merge +def asm_xtensa(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code for the esp8266. + The assembler code is written in the Xtensa instruction set, and is executed on the target CPU. + + Availability: Only on eps8266 boards. + """ + ... + # See : + # - https://github.com/orgs/micropython/discussions/12965 + # - https://github.com/micropython/micropython/pull/16731 diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/mimxrt.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/mimxrt.pyi new file mode 100644 index 000000000..8ecccefdf --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/mimxrt.pyi @@ -0,0 +1,14 @@ +""" +Module: 'mimxrt' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class Flash: + def readblocks(self, *args, **kwargs) -> Incomplete: ... + def writeblocks(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/mip/__init__.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/mip/__init__.pyi new file mode 100644 index 000000000..466c68177 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/mip/__init__.pyi @@ -0,0 +1,38 @@ +""" +Module: 'mip.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +allowed_mip_url_prefixes: tuple = () +_CHUNK_SIZE: Final[int] = 128 +def _ensure_path_exists(*args, **kwargs) -> Incomplete: + ... + +def _install_json(*args, **kwargs) -> Incomplete: + ... + +def _install_package(*args, **kwargs) -> Incomplete: + ... + +def _rewrite_url(*args, **kwargs) -> Incomplete: + ... + +def install(*args, **kwargs) -> Incomplete: + ... + +def _download_file(*args, **kwargs) -> Incomplete: + ... + +def const(*args, **kwargs) -> Incomplete: + ... + +def _check_exists(*args, **kwargs) -> Incomplete: + ... + +def _chunk(*args, **kwargs) -> Incomplete: + ... + diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/network.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/network.pyi new file mode 100644 index 000000000..9ffd68e9d --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/network.pyi @@ -0,0 +1,551 @@ +""" +Network configuration. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/network.html + +This module provides network drivers and routing configuration. To use this +module, a MicroPython variant/build with network capabilities must be installed. +Network drivers for specific hardware are available within this module and are +used to configure hardware network interface(s). Network services provided +by configured interfaces are then available for use via the :mod:`socket` +module. + +For example:: + + # connect/ show IP config a specific network interface + # see below for examples of specific drivers + import network + import time + nic = network.Driver(...) + if not nic.isconnected(): + nic.connect() + print("Waiting for connection...") + while not nic.isconnected(): + time.sleep(1) + print(nic.ipconfig("addr4")) + + # now use socket as usual + import socket + addr = socket.getaddrinfo('micropython.org', 80)[0][-1] + s = socket.socket() + s.connect(addr) + s.send(b'GET / HTTP/1.1 +Host: micropython.org + +') + data = s.recv(1000) + s.close() + +--- +Module: 'network' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Protocol, Callable, overload, Any, List, Optional, Tuple, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar +from machine import Pin, SPI +from abc import abstractmethod + +STA_IF: Final[int] = 0 +AP_IF: Final[int] = 1 + +def route(*args, **kwargs) -> Incomplete: ... +def hostname(name: Optional[Any] = None) -> Incomplete: + """ + Get or set the hostname that will identify this device on the network. It will + be used by all interfaces. + + This hostname is used for: + * Sending to the DHCP server in the client request. (If using DHCP) + * Broadcasting via mDNS. (If enabled) + + If the *name* parameter is provided, the hostname will be set to this value. + If the function is called without parameters, it returns the current + hostname. + + A change in hostname is typically only applied during connection. For DHCP + this is because the hostname is part of the DHCP client request, and the + implementation of mDNS in most ports only initialises the hostname once + during connection. For this reason, you must set the hostname before + activating/connecting your network interfaces. + + The length of the hostname is limited to 32 characters. + :term:`MicroPython ports ` may choose to set a lower + limit for memory reasons. If the given name does not fit, a `ValueError` + is raised. + + The default hostname is typically the name of the board. + """ + ... + +def ipconfig(param: Optional[str] = None, *args, **kwargs) -> str: + """ + Get or set global IP-configuration parameters. + Supported parameters are the following (availability of a particular + parameter depends on the port and the specific network interface): + + * ``dns`` Get/set DNS server. This method can support both, IPv4 and + IPv6 addresses. + * ``prefer`` (``4/6``) Specify which address type to return, if a domain + name has both A and AAAA records. Note, that this does not clear the + local DNS cache, so that any previously obtained addresses might not + change. + """ + ... + +def country(code: Optional[Any] = None) -> Incomplete: + """ + Get or set the two-letter ISO 3166-1 Alpha-2 country code to be used for + radio compliance. + + If the *code* parameter is provided, the country will be set to this value. + If the function is called without parameters, it returns the current + country. + + The default code ``"XX"`` represents the "worldwide" region. + """ + ... + +class PPP: + """ + Create a PPP driver object. + + Arguments are: + + - *stream* is any object that supports the stream protocol, but is most commonly a + :class:`machine.UART` instance. This stream object must have an ``irq()`` method + and an ``IRQ_RXIDLE`` constant, for use by `PPP.connect`. + """ + + SEC_NONE: Final[int] = 0 + """The type of connection security.""" + SEC_PAP: Final[int] = 1 + """The type of connection security.""" + SEC_CHAP: Final[int] = 2 + """The type of connection security.""" + def status(self) -> Incomplete: + """ + Returns the PPP status. + """ + ... + def ipconfig(self, param) -> Incomplete: + """ + See `AbstractNIC.ipconfig`. + """ + ... + def isconnected(self) -> bool: + """ + Returns ``True`` if the PPP link is connected and up. + Returns ``False`` otherwise. + """ + ... + def poll(self) -> Incomplete: + """ + Poll the underlying stream for data, and pass it up the PPP stack. + This is called automatically if the stream is a UART with a RXIDLE interrupt, + so it's not usually necessary to call it manually. + """ + ... + def ifconfig(self, configtuple: Any | None = None) -> Incomplete: + """ + See `AbstractNIC.ifconfig`. + """ + ... + def config(self, config_parameters) -> Incomplete: + """ + Sets or gets parameters of the PPP interface. The only parameter that can be + retrieved and set is the underlying stream, using:: + + stream = PPP.config("stream") + PPP.config(stream=stream) + """ + ... + def connect(self, security=SEC_NONE, user=None, key=None) -> Incomplete: + """ + Initiate a PPP connection with the given parameters: + + - *security* is the type of security, either ``PPP.SEC_NONE``, ``PPP.SEC_PAP``, + or ``PPP.SEC_CHAP``. + - *user* is an optional user name to use with the security mode. + - *key* is an optional password to use with the security mode. + + When this method is called the underlying stream has its interrupt configured to call + `PPP.poll` via ``stream.irq(ppp.poll, stream.IRQ_RXIDLE)``. This makes sure the + stream is polled, and data passed up the PPP stack, wheverver data becomes available + on the stream. + + The connection proceeds asynchronously, in the background. + """ + ... + def disconnect(self) -> Incomplete: + """ + Terminate the connection. This must be called to cleanly close the PPP connection. + """ + ... + def __init__(self, stream) -> None: ... + +class LAN: + """ + Create a LAN driver object, initialise the LAN module using the given + PHY driver name, and return the LAN object. + + Arguments are: + + - *id* is the number of the Ethernet port, either 0 or 1. + - *phy_type* is the name of the PHY driver. For most board the on-board PHY has to be used and + is the default. Suitable values are port specific. + - *phy_addr* specifies the address of the PHY interface. As with *phy_type*, the hardwired value has + to be used for most boards and that value is the default. + - *ref_clk_mode* specifies, whether the data clock is provided by the Ethernet controller or + the PYH interface. + The default value is the one that matches the board. If set to ``LAN.OUT`` or ``Pin.OUT`` + or ``True``, the clock is driven by the Ethernet controller, if set to ``LAN.IN`` + or ``Pin.IN`` or ``False``, the clock is driven by the PHY interface. + + For example, with the Seeed Arch Mix board you can use:: + + nic = LAN(0, phy_type=LAN.PHY_LAN8720, phy_addr=1, ref_clk_mode=Pin.IN) + """ + + PHY_KSZ8081: Final[int] = 0 + PHY_DP83848: Final[int] = 2 + PHY_LAN8720: Final[int] = 3 + PHY_RTL8211F: Final[int] = 4 + IN: Final[int] = 0 + PHY_DP83825: Final[int] = 1 + OUT: Final[int] = 1 + def ipconfig(self, *args, **kwargs) -> Incomplete: ... + def status(self) -> Incomplete: + """ + Returns the LAN status. + """ + ... + def isconnected(self) -> bool: + """ + Returns ``True`` if the physical Ethernet link is connected and up. + Returns ``False`` otherwise. + """ + ... + @overload + def active(self, /) -> bool: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ + + @overload + def active(self, is_active: bool | int, /) -> None: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ + def ifconfig(self, configtuple: Any | None = None) -> Tuple: + """ + Get/set IP address, subnet mask, gateway and DNS. + + When called with no arguments, this method returns a 4-tuple with the above information. + + To set the above values, pass a 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + ... + def config(self, config_parameters) -> Incomplete: + """ + Sets or gets parameters of the LAN interface. The only parameter that can be + retrieved is the MAC address, using:: + + mac = LAN.config("mac") + + The parameters that can be set are: + + - ``trace=n`` sets trace levels; suitable values are: + + - 2: trace TX + - 4: trace RX + - 8: full trace + + - ``low_power=bool`` sets or clears low power mode, valid values being ``False`` + or ``True``. + """ + ... + def __init__(self, id, *, phy_type=0, phy_addr=0, ref_clk_mode=0) -> None: ... + +class WLANWiPy: + @overload + def __init__(self, id: int = 0, /): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int, + ssid: str, + auth: tuple[str, str], + channel: int, + antenna: int, + ): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def mode(self) -> int: + """ + Get or set the WLAN mode. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the WLAN mode. + """ + + @overload + def ssid(self) -> str: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def ssid(self, ssid: str, /) -> None: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def auth(self) -> int: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def auth(self, auth: int, /) -> None: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def channel(self) -> int: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def channel(self, channel: int, /) -> None: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def antenna(self) -> int: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def antenna(self, antenna: int, /) -> None: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def mac(self) -> bytes: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + + @overload + def mac(self, mac: bytes, /) -> None: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + +class AbstractNIC: + @overload + @abstractmethod + def active(self, /) -> bool: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def active(self, is_active: bool | int, /) -> None: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def connect(self, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def connect(self, service_id: Any, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def status(self) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def status(self, param: str, /) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def ifconfig(self) -> tuple[str, str, str, str]: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def ifconfig(self, ip_mask_gateway_dns: tuple[str, str, str, str], /) -> None: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def config(self, param: str, /) -> Any: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ + + @overload + @abstractmethod + def config(self, **kwargs: Any) -> None: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ntptime.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ntptime.pyi new file mode 100644 index 000000000..617a66875 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ntptime.pyi @@ -0,0 +1,15 @@ +""" +Module: 'ntptime' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +timeout: int = 1 +host: str = "pool.ntp.org" + +def time(*args, **kwargs) -> Incomplete: ... +def settime(*args, **kwargs) -> Incomplete: ... +def gmtime(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/onewire.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/onewire.pyi new file mode 100644 index 000000000..4994ced18 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/onewire.pyi @@ -0,0 +1,28 @@ +""" +Module: 'onewire' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SKIP_ROM: Final[int] = 204 + SEARCH_ROM: Final[int] = 240 + MATCH_ROM: Final[int] = 85 + def select_rom(self, *args, **kwargs) -> Incomplete: ... + def writebit(self, *args, **kwargs) -> Incomplete: ... + def writebyte(self, *args, **kwargs) -> Incomplete: ... + def _search_rom(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def crc8(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def reset(self, *args, **kwargs) -> Incomplete: ... + def readbit(self, *args, **kwargs) -> Incomplete: ... + def readbyte(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/platform.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/platform.pyi new file mode 100644 index 000000000..a84342847 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/platform.pyi @@ -0,0 +1,51 @@ +""" +Access to underlying platform’s identifying data. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/platform.html + +CPython module: :mod:`python:platform` https://docs.python.org/3/library/platform.html . + +This module tries to retrieve as much platform-identifying data as possible. It +makes this information available via function APIs. + +--- +Module: 'platform' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def platform() -> str: + """ + Returns a string identifying the underlying platform. This string is composed + of several substrings in the following order, delimited by dashes (``-``): + + - the name of the platform system (e.g. Unix, Windows or MicroPython) + - the MicroPython version + - the architecture of the platform + - the version of the underlying platform + - the concatenation of the name of the libc that MicroPython is linked to + and its corresponding version. + + For example, this could be + ``"MicroPython-1.20.0-xtensa-IDFv4.2.4-with-newlib3.0.0"``. + """ + ... + +def python_compiler() -> str: + """ + Returns a string identifying the compiler used for compiling MicroPython. + """ + ... + +def libc_ver() -> Tuple: + """ + Returns a tuple of strings *(lib, version)*, where *lib* is the name of the + libc that MicroPython is linked to, and *version* the corresponding version + of this libc. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/random.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/random.pyi new file mode 100644 index 000000000..52c922661 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/random.pyi @@ -0,0 +1,115 @@ +""" +Random numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/random.html + +This module implements a pseudo-random number generator (PRNG). + +CPython module: :mod:`python:random` https://docs.python.org/3/library/random.html . . + +.. note:: + + The following notation is used for intervals: + + - () are open interval brackets and do not include their endpoints. + For example, (0, 1) means greater than 0 and less than 1. + In set notation: (0, 1) = {x | 0 < x < 1}. + + - [] are closed interval brackets which include all their limit points. + For example, [0, 1] means greater than or equal to 0 and less than + or equal to 1. + In set notation: [0, 1] = {x | 0 <= x <= 1}. + +.. note:: + + The :func:`randrange`, :func:`randint` and :func:`choice` functions are only + available if the ``MICROPY_PY_RANDOM_EXTRA_FUNCS`` configuration option is + enabled. + +--- +Module: 'random' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import Subscriptable +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +@overload +def randrange(stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, step: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +def random() -> int: + """ + Return a random floating point number in the range [0.0, 1.0). + """ + ... + +def seed(n: int | None = None, /) -> None: + """ + Initialise the random number generator module with the seed *n* which should + be an integer. When no argument (or ``None``) is passed in it will (if + supported by the port) initialise the PRNG with a true random number + (usually a hardware generated random number). + + The ``None`` case only works if ``MICROPY_PY_RANDOM_SEED_INIT_FUNC`` is + enabled by the port, otherwise it raises ``ValueError``. + """ + ... + +def uniform(a: float, b: float) -> int: + """ + Return a random floating point number N such that *a* <= N <= *b* for *a* <= *b*, + and *b* <= N <= *a* for *b* < *a*. + """ + ... + +def choice(sequence: Subscriptable, /) -> None: + """ + Chooses and returns one item at random from *sequence* (tuple, list or + any object that supports the subscript operation). + """ + ... + +def randint(a: int, b: int, /) -> int: + """ + Return a random integer in the range [*a*, *b*]. + """ + ... + +def getrandbits(n: int, /) -> int: + """ + Return an integer with *n* random bits (0 <= n <= 32). + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/requests/__init__.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/requests/__init__.pyi new file mode 100644 index 000000000..2ea7932fc --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/requests/__init__.pyi @@ -0,0 +1,42 @@ +""" +Module: 'requests.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def head(*args, **kwargs) -> Incomplete: + ... + +def patch(*args, **kwargs) -> Incomplete: + ... + +def post(*args, **kwargs) -> Incomplete: + ... + +def put(*args, **kwargs) -> Incomplete: + ... + +def request(*args, **kwargs) -> Incomplete: + ... + +def delete(*args, **kwargs) -> Incomplete: + ... + +def get(*args, **kwargs) -> Incomplete: + ... + + +class Response(): + def json(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + content: Incomplete ## = + text: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: + ... + diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/select.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/select.pyi new file mode 100644 index 000000000..c1893e88b --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/select.pyi @@ -0,0 +1,118 @@ +""" +Wait for events on a set of streams. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/select.html + +CPython module: :mod:`python:select` https://docs.python.org/3/library/select.html . + +This module provides functions to efficiently wait for events on multiple +`streams ` (select streams which are ready for operations). + +--- +Module: 'select' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Iterable, Iterator, List, Optional, Tuple, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +POLLOUT: Final[int] = 4 +POLLIN: Final[int] = 1 +POLLHUP: Final[int] = 16 +POLLERR: Final[int] = 8 + +def select( + rlist: Iterable[Any], + wlist: Iterable[Any], + xlist: Iterable[Any], + timeout: int = -1, + /, +) -> None: + """ + Wait for activity on a set of objects. + + This function is provided by some MicroPython ports for compatibility + and is not efficient. Usage of :class:`Poll` is recommended instead. + """ + ... + +class poll: + """ + Create an instance of the Poll class. + """ + def __init__(self) -> None: ... + def register(self, obj, eventmask: Optional[Any] = None) -> None: + """ + Register `stream` *obj* for polling. *eventmask* is logical OR of: + + * ``select.POLLIN`` - data available for reading + * ``select.POLLOUT`` - more data can be written + + Note that flags like ``select.POLLHUP`` and ``select.POLLERR`` are + *not* valid as input eventmask (these are unsolicited events which + will be returned from `poll()` regardless of whether they are asked + for). This semantics is per POSIX. + + *eventmask* defaults to ``select.POLLIN | select.POLLOUT``. + + It is OK to call this function multiple times for the same *obj*. + Successive calls will update *obj*'s eventmask to the value of + *eventmask* (i.e. will behave as `modify()`). + """ + ... + def unregister(self, obj) -> Incomplete: + """ + Unregister *obj* from polling. + """ + ... + def modify(self, obj, eventmask) -> None: + """ + Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError` + is raised with error of ENOENT. + """ + ... + def poll(self, timeout=-1, /) -> List: + """ + Wait for at least one of the registered objects to become ready or have an + exceptional condition, with optional timeout in milliseconds (if *timeout* + arg is not specified or -1, there is no timeout). + + Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in + tuple, depending on a platform and version, so don't assume that its size is 2. + The ``event`` element specifies which events happened with a stream and + is a combination of ``select.POLL*`` constants described above. Note that + flags ``select.POLLHUP`` and ``select.POLLERR`` can be returned at any time + (even if were not asked for), and must be acted on accordingly (the + corresponding stream unregistered from poll and likely closed), because + otherwise all further invocations of `poll()` may return immediately with + these flags set for this stream again. + + In case of timeout, an empty list is returned. + + Admonition:Difference to CPython + :class: attention + + Tuples returned may contain more than 2 elements as described above. + """ + ... + def ipoll(self, timeout=-1, flags=0, /) -> Iterator[Tuple]: + """ + Like :meth:`poll.poll`, but instead returns an iterator which yields a + `callee-owned tuple`. This function provides an efficient, allocation-free + way to poll on streams. + + If *flags* is 1, one-shot behaviour for events is employed: streams for + which events happened will have their event masks automatically reset + (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream + won't be processed until new mask is set with `poll.modify()`. This + behaviour is useful for asynchronous I/O schedulers. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/socket.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/socket.pyi new file mode 100644 index 000000000..9acb73654 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/socket.pyi @@ -0,0 +1,426 @@ +""" +Socket module. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/socket.html + +CPython module: :mod:`python:socket` https://docs.python.org/3/library/socket.html . + +This module provides access to the BSD socket interface. + +Admonition:Difference to CPython + :class: attention + + For efficiency and consistency, socket objects in MicroPython implement a `stream` + (file-like) interface directly. In CPython, you need to convert a socket to + a file-like object using `makefile()` method. This method is still supported + by MicroPython (but is a no-op), so where compatibility with CPython matters, + be sure to use it. + +Socket address format(s) +------------------------ + +The native socket address format of the ``socket`` module is an opaque data type +returned by `getaddrinfo` function, which must be used to resolve textual address +(including numeric addresses):: + + sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1] + # You must use getaddrinfo() even for numeric addresses + sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1] + # Now you can use that address + sock.connect(sockaddr) + +Using `getaddrinfo` is the most efficient (both in terms of memory and processing +power) and portable way to work with addresses. + +However, ``socket`` module (note the difference with native MicroPython +``socket`` module described here) provides CPython-compatible way to specify +addresses using tuples, as described below. Note that depending on a +:term:`MicroPython port`, ``socket`` module can be builtin or need to be +installed from `micropython-lib` (as in the case of :term:`MicroPython Unix port`), +and some ports still accept only numeric addresses in the tuple format, +and require to use `getaddrinfo` function to resolve domain names. + +Summing up: + +* Always use `getaddrinfo` when writing portable applications. +* Tuple addresses described below can be used as a shortcut for + quick hacks and interactive use, if your port supports them. + +Tuple address format for ``socket`` module: + +* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with + dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and + integer port number in the range 1-65535. Note the domain names are not + accepted as *ipv4_address*, they should be resolved first using + `socket.getaddrinfo()`. +* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address* + is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``, + and *port* is an integer port number in the range 1-65535. *flowinfo* + must be 0. *scopeid* is the interface scope identifier for link-local + addresses. Note the domain names are not accepted as *ipv6_address*, + they should be resolved first using `socket.getaddrinfo()`. Availability + of IPv6 support depends on a :term:`MicroPython port`. + +--- +Module: 'socket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Literal, Tuple, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +SOCK_RAW: Final[int] = 3 +SOCK_STREAM: Final[int] = 1 +"""Socket types.""" +SOCK_DGRAM: Final[int] = 2 +"""Socket types.""" +MSG_PEEK: Final[int] = 1 +SO_REUSEADDR: Final[int] = 4 +SOL_SOCKET: Final[int] = 1 +SO_BROADCAST: Final[int] = 32 +TCP_NODELAY: Final[int] = 64 +AF_INET6: Final[int] = 10 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +IPPROTO_IP: Final[int] = 0 +AF_INET: Final[int] = 2 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +MSG_DONTWAIT: Final[int] = 2 +IP_DROP_MEMBERSHIP: Final[int] = 1025 +IPPROTO_TCP: Final[int] = 6 +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IP_ADD_MEMBERSHIP: Final[int] = 1024 +IPPROTO_UDP: Incomplete +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IPPROTO_SEC: Incomplete +"""Special protocol value to create SSL-compatible socket.""" +_Address: TypeAlias = tuple[str, int] | tuple[str, int, int, int] | str +Socket: TypeAlias = socket + +def reset(*args, **kwargs) -> Incomplete: ... +def print_pcbs(*args, **kwargs) -> Incomplete: ... +def getaddrinfo( + host: str, + port: int, + af: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, + /, +) -> list[tuple[int, int, int, str, tuple[str, int] | tuple[str, int, int, int]]]: + """ + Translate the host/port argument into a sequence of 5-tuples that contain all the + necessary arguments for creating a socket connected to that service. Arguments + *af*, *type*, and *proto* (which have the same meaning as for the `socket()` function) + can be used to filter which kind of addresses are returned. If a parameter is not + specified or zero, all combinations of addresses can be returned (requiring + filtering on the user side). + + The resulting list of 5-tuples has the following structure:: + + (family, type, proto, canonname, sockaddr) + + The following example shows how to connect to a given url:: + + s = socket.socket() + # This assumes that if "type" is not specified, an address for + # SOCK_STREAM will be returned, which may be not true + s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1]) + + Recommended use of filtering params:: + + s = socket.socket() + # Guaranteed to return an address which can be connect'ed to for + # stream operation. + s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1]) + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.gaierror`` exception (`OSError` subclass) in case + of error in this function. MicroPython doesn't have ``socket.gaierror`` + and raises OSError directly. Note that error numbers of `getaddrinfo()` + form a separate namespace and may not match error numbers from + the :mod:`errno` module. To distinguish `getaddrinfo()` errors, they are + represented by negative numbers, whereas standard system errors are + positive numbers (error numbers are accessible using ``e.args[0]`` property + from an exception object). The use of negative values is a provisional + detail which may change in the future. + """ + ... + +def callback(*args, **kwargs) -> Incomplete: ... + +class socket: + """ + A unix like socket, for more information see module ``socket``'s description. + + The name, `Socket`, used for typing is not the same as the runtime name, `socket` (note lowercase `s`). + The reason for this difference is that the runtime uses `socket` as both a class name and as a method name and + this is not possible within code written entirely in Python and therefore not possible within typing code. + """ + def recvfrom(self, bufsize: int, /) -> Tuple: + """ + Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a + bytes object representing the data received and *address* is the address of the socket sending + the data. + + See the `recv` function for an explanation of the optional *flags* argument. + """ + ... + def recv(self, bufsize: int, /) -> bytes: + """ + Receive data from the socket. The return value is a bytes object representing the data + received. The maximum amount of data to be received at once is specified by bufsize. + + Most ports support the optional *flags* argument. Available *flags* are defined as constants + in the socket module and have the same meaning as in CPython. ``MSG_PEEK`` and ``MSG_DONTWAIT`` + are supported on all ports which accept the *flags* argument. + """ + ... + + @overload + def makefile(self, mode: Literal["rb", "wb", "rwb"] = "rb", buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + + @overload + def makefile(self, mode: str, buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + def listen(self, backlog: int = ..., /) -> None: + """ + Enable a server to accept connections. If *backlog* is specified, it must be at least 0 + (if it's lower, it will be set to 0); and specifies the number of unaccepted connections + that the system will allow before refusing new connections. If not specified, a default + reasonable value is chosen. + """ + ... + def settimeout(self, value: float | None, /) -> None: + """ + **Note**: Not every port supports this method, see below. + + Set a timeout on blocking socket operations. The value argument can be a nonnegative floating + point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations + will raise an `OSError` exception if the timeout period value has elapsed before the operation has + completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket + is put in blocking mode. + + Not every :term:`MicroPython port` supports this method. A more portable and + generic solution is to use `select.poll` object. This allows to wait on + multiple objects at the same time (and not just on sockets, but on generic + `stream` objects which support polling). Example:: + + # Instead of: + s.settimeout(1.0) # time in seconds + s.read(10) # may timeout + + # Use: + poller = select.poll() + poller.register(s, select.POLLIN) + res = poller.poll(1000) # time in milliseconds + if not res: + # s is still not ready for input, i.e. operation timed out + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.timeout`` exception in case of timeout, + which is an `OSError` subclass. MicroPython raises an OSError directly + instead. If you use ``except OSError:`` to catch the exception, + your code will work both in MicroPython and CPython. + """ + ... + def sendall(self, bytes: AnyReadableBuf, /) -> int: + """ + Send all data to the socket. The socket must be connected to a remote socket. + Unlike `send()`, this method will try to send all of data, by sending data + chunk by chunk consecutively. + + The behaviour of this method on non-blocking sockets is undefined. Due to this, + on MicroPython, it's recommended to use `write()` method instead, which + has the same "no short writes" policy for blocking sockets, and will return + number of bytes sent on non-blocking sockets. + """ + ... + def setsockopt(self, level: int, optname: int, value: AnyReadableBuf | int, /) -> None: + """ + Set the value of the given socket option. The needed symbolic constants are defined in the + socket module (SO_* etc.). The *value* can be an integer or a bytes-like object representing + a buffer. + """ + ... + def setblocking(self, value: bool, /) -> None: + """ + Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking, + else to blocking mode. + + This method is a shorthand for certain `settimeout()` calls: + + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)`` + """ + ... + def sendto(self, bytes: AnyReadableBuf, address: _Address, /) -> None: + """ + Send data to the socket. The socket should not be connected to a remote socket, since the + destination socket is specified by *address*. + """ + ... + def readline(self) -> bytes: + """ + Read a line, ending in a newline character. + + Return value: the line read. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def read(self) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + + @overload + def read(self, size: int, /) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + def close(self) -> None: + """ + Mark the socket closed and release all resources. Once that happens, all future operations + on the socket object will fail. The remote end will receive EOF indication if + supported by protocol. + + Sockets are automatically closed when they are garbage-collected, but it is recommended + to `close()` them explicitly as soon you finished working with them. + """ + ... + def connect(self, address: _Address | bytes, /) -> None: + """ + Connect to a remote socket at *address*. + """ + ... + def send(self, bytes: AnyReadableBuf, /) -> int: + """ + Send data to the socket. The socket must be connected to a remote socket. + Returns number of bytes sent, which may be smaller than the length of data + ("short write"). + """ + ... + def bind(self, address: _Address | bytes, /) -> None: + """ + Bind the socket to *address*. The socket must not already be bound. + """ + ... + def accept(self) -> Tuple: + """ + Accept a connection. The socket must be bound to an address and listening for connections. + The return value is a pair (conn, address) where conn is a new socket object usable to send + and receive data on the connection, and address is the address bound to the socket on the + other end of the connection. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the buffer of bytes to the socket. This function will try to + write all data to a socket (no "short writes"). This may be not possible + with a non-blocking socket though, and returned value will be less than + the length of *buf*. + + Return value: number of bytes written. + """ + ... + def __init__( + self, + af: int = AF_INET, + type: int = SOCK_STREAM, + proto: int = IPPROTO_TCP, + /, + ) -> None: + """ + Create a new socket using the given address family, socket type and + protocol number. Note that specifying *proto* in most cases is not + required (and not recommended, as some MicroPython ports may omit + ``IPPROTO_*`` constants). Instead, *type* argument will select needed + protocol automatically:: + + # Create STREAM TCP socket + socket(AF_INET, SOCK_STREAM) + # Create DGRAM UDP socket + socket(AF_INET, SOCK_DGRAM) + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/time.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/time.pyi new file mode 100644 index 000000000..1f091db69 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/time.pyi @@ -0,0 +1,306 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. + +--- +Module: 'time' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def ticks_diff(ticks1: _Ticks, ticks2: _Ticks, /) -> int: + """ + Measure ticks difference between values returned from `ticks_ms()`, `ticks_us()`, + or `ticks_cpu()` functions, as a signed value which may wrap around. + + The argument order is the same as for subtraction + operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. + However, values returned by `ticks_ms()`, etc. functions may wrap around, so + directly using subtraction on them will produce incorrect result. That is why + `ticks_diff()` is needed, it implements modular (or more specifically, ring) + arithmetic to produce correct result even for wrap-around values (as long as they not + too distant in between, see below). The function returns **signed** value in the range + [*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for + two's-complement signed binary integers). If the result is negative, it means that + *ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that + *ticks1* occurred after *ticks2*. This holds **only** if *ticks1* and *ticks2* + are apart from each other for no more than *TICKS_PERIOD/2-1* ticks. If that does + not hold, incorrect result will be returned. Specifically, if two tick values are + apart for *TICKS_PERIOD/2-1* ticks, that value will be returned by the function. + However, if *TICKS_PERIOD/2* of real-time ticks has passed between them, the + function will return *-TICKS_PERIOD/2* instead, i.e. result value will wrap around + to the negative range of possible values. + + Informal rationale of the constraints above: Suppose you are locked in a room with no + means to monitor passing of time except a standard 12-notch clock. Then if you look at + dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a + long sleep), then once you finally look again, it may seem to you that only 1 hour + has passed. To avoid this mistake, just look at the clock regularly. Your application + should do the same. "Too long sleep" metaphor also maps directly to application + behaviour: don't let your application run any single task for too long. Run tasks + in steps, and do time-keeping in between. + + `ticks_diff()` is designed to accommodate various usage patterns, among them: + + * Polling with timeout. In this case, the order of events is known, and you will deal + only with positive results of `ticks_diff()`:: + + # Wait for GPIO pin to be asserted, but at most 500us + start = time.ticks_us() + while pin.value() == 0: + if time.ticks_diff(time.ticks_us(), start) > 500: + raise TimeoutError + + * Scheduling events. In this case, `ticks_diff()` result may be negative + if an event is overdue:: + + # This code snippet is not optimized + now = time.ticks_ms() + scheduled_time = task.scheduled_time() + if ticks_diff(scheduled_time, now) > 0: + print("Too early, let's nap") + sleep_ms(ticks_diff(scheduled_time, now)) + task.run() + elif ticks_diff(scheduled_time, now) == 0: + print("Right at time!") + task.run() + elif ticks_diff(scheduled_time, now) < 0: + print("Oops, running late, tell task to run faster!") + task.run(run_faster=true) + + Note: Do not pass `time()` values to `ticks_diff()`, you should use + normal mathematical operations on them. But note that `time()` may (and will) + also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem . + """ + ... + +def ticks_add(ticks: _Ticks, delta: int, /) -> _Ticks: + """ + Offset ticks value by a given number, which can be either positive or negative. + Given a *ticks* value, this function allows to calculate ticks value *delta* + ticks before or after it, following modular-arithmetic definition of tick values + (see `ticks_ms()` above). *ticks* parameter must be a direct result of call + to `ticks_ms()`, `ticks_us()`, or `ticks_cpu()` functions (or from previous + call to `ticks_add()`). However, *delta* can be an arbitrary integer number + or numeric expression. `ticks_add()` is useful for calculating deadlines for + events/tasks. (Note: you must use `ticks_diff()` function to work with + deadlines.) + + Examples:: + + # Find out what ticks value there was 100ms ago + print(ticks_add(time.ticks_ms(), -100)) + + # Calculate deadline for operation and test for it + deadline = ticks_add(time.ticks_ms(), 200) + while ticks_diff(deadline, time.ticks_ms()) > 0: + do_a_little_of_something() + + # Find out TICKS_MAX used by this port + print(ticks_add(0, -1)) + """ + ... + +def ticks_cpu() -> _TicksCPU: + """ + Similar to `ticks_ms()` and `ticks_us()`, but with the highest possible resolution + in the system. This is usually CPU clocks, and that's why the function is named that + way. But it doesn't have to be a CPU clock, some other timing source available in a + system (e.g. high-resolution timer) can be used instead. The exact timing unit + (resolution) of this function is not specified on ``time`` module level, but + documentation for a specific port may provide more specific information. This + function is intended for very fine benchmarking or very tight real-time loops. + Avoid using it in portable code. + + Availability: Not every port implements this function. + """ + ... + +def time() -> int: + """ + Returns the number of seconds, as an integer, since the Epoch, assuming that + underlying RTC is set and maintained as described above. If an RTC is not set, this + function returns number of seconds since a port-specific reference point in time (for + embedded boards without a battery-backed RTC, usually since power up or reset). If you + want to develop portable MicroPython application, you should not rely on this function + to provide higher than second precision. If you need higher precision, absolute + timestamps, use `time_ns()`. If relative times are acceptable then use the + `ticks_ms()` and `ticks_us()` functions. If you need calendar time, `gmtime()` or + `localtime()` without an argument is a better choice. + + Admonition:Difference to CPython + :class: attention + + In CPython, this function returns number of + seconds since Unix epoch, 1970-01-01 00:00 UTC, as a floating-point, + usually having microsecond precision. With MicroPython, only Unix port + uses the same Epoch, and if floating-point precision allows, + returns sub-second precision. Embedded hardware usually doesn't have + floating-point precision to represent both long time ranges and subsecond + precision, so they use integer value with second precision. Some embedded + hardware also lacks battery-powered RTC, so returns number of seconds + since last power-up or from other relative, hardware-specific point + (e.g. reset). + """ + ... + +def ticks_ms() -> int: + """ + Returns an increasing millisecond counter with an arbitrary reference point, that + wraps around after some value. + + The wrap-around value is not explicitly exposed, but we will + refer to it as *TICKS_MAX* to simplify discussion. Period of the values is + *TICKS_PERIOD = TICKS_MAX + 1*. *TICKS_PERIOD* is guaranteed to be a power of + two, but otherwise may differ from port to port. The same period value is used + for all of `ticks_ms()`, `ticks_us()`, `ticks_cpu()` functions (for + simplicity). Thus, these functions will return a value in range [*0* .. + *TICKS_MAX*], inclusive, total *TICKS_PERIOD* values. Note that only + non-negative values are used. For the most part, you should treat values returned + by these functions as opaque. The only operations available for them are + `ticks_diff()` and `ticks_add()` functions described below. + + Note: Performing standard mathematical operations (+, -) or relational + operators (<, <=, >, >=) directly on these value will lead to invalid + result. Performing mathematical operations and then passing their results + as arguments to `ticks_diff()` or `ticks_add()` will also lead to + invalid results from the latter functions. + """ + ... + +def ticks_us() -> _TicksUs: + """ + Just like `ticks_ms()` above, but in microseconds. + """ + ... + +def time_ns() -> int: + """ + Similar to `time()` but returns nanoseconds since the Epoch, as an integer (usually + a big integer, so will allocate on the heap). + """ + ... + +def localtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_us(us: int, /) -> None: + """ + Delay for given number of microseconds, should be positive or 0. + + This function attempts to provide an accurate delay of at least *us* + microseconds, but it may take longer if the system has other higher priority + processing to perform. + """ + ... + +def gmtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_ms(ms: int, /) -> None: + """ + Delay for given number of milliseconds, should be positive or 0. + + This function will delay for at least the given number of milliseconds, but + may take longer than that if other processing must take place, for example + interrupt handlers or other threads. Passing in 0 for *ms* will still allow + this other processing to occur. Use `sleep_us()` for more precise delays. + """ + ... + +def mktime(local_time: _TimeTuple, /) -> int: + """ + This is inverse function of localtime. It's argument is a full 8-tuple + which expresses a time as per localtime. It returns an integer which is + the number of seconds since the time epoch. + """ + ... + +def sleep(seconds: float, /) -> None: + """ + Sleep for the given number of seconds. Some boards may accept *seconds* as a + floating-point number to sleep for a fractional number of seconds. Note that + other boards may not accept a floating-point argument, for compatibility with + them use `sleep_ms()` and `sleep_us()` functions. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/tls.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/tls.pyi new file mode 100644 index 000000000..34f93f51e --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/tls.pyi @@ -0,0 +1,26 @@ +""" +Module: 'tls' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +PROTOCOL_TLS_SERVER: Final[int] = 1 +PROTOCOL_DTLS_CLIENT: Final[int] = 2 +PROTOCOL_DTLS_SERVER: Final[int] = 3 +PROTOCOL_TLS_CLIENT: Final[int] = 0 +MBEDTLS_VERSION: Final[str] = "Mbed TLS 3.6.2" +CERT_NONE: Final[int] = 0 +CERT_OPTIONAL: Final[int] = 1 +CERT_REQUIRED: Final[int] = 2 + +class SSLContext: + def load_verify_locations(self, *args, **kwargs) -> Incomplete: ... + def set_ciphers(self, *args, **kwargs) -> Incomplete: ... + def wrap_socket(self, *args, **kwargs) -> Incomplete: ... + def load_cert_chain(self, *args, **kwargs) -> Incomplete: ... + def get_ciphers(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uarray.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uarray.pyi new file mode 100644 index 000000000..e5c0fe438 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uarray.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to array +from array import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uasyncio.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uasyncio.pyi new file mode 100644 index 000000000..3d69c52f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uasyncio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to asyncio +from asyncio import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ubinascii.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ubinascii.pyi new file mode 100644 index 000000000..3a77380ad --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ubinascii.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to binascii +from binascii import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ubluetooth.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ubluetooth.pyi new file mode 100644 index 000000000..4046c2c75 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ubluetooth.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to bluetooth +from bluetooth import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ucollections.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ucollections.pyi new file mode 100644 index 000000000..03856605f --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ucollections.pyi @@ -0,0 +1,137 @@ +""" +Collection and container types. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/collections.html + +CPython module: :mod:`python:collections` https://docs.python.org/3/library/collections.html . + +This module implements advanced collection and container types to +hold/accumulate various objects. + +--- +Module: 'ucollections' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Generic, Tuple, Any, Final, Generator +from _typeshed import Incomplete +from collections.abc import Iterable +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_KT = TypeVar("_KT") +_VT = TypeVar("_VT") +_T = TypeVar("_T") + +def namedtuple(name: str, fields: str | Iterable[str]) -> type[Tuple[Any, ...]]: + """ + This is factory function to create a new namedtuple type with a specific + name and set of fields. A namedtuple is a subclass of tuple which allows + to access its fields not just by numeric index, but also with an attribute + access syntax using symbolic field names. Fields is a sequence of strings + specifying field names. For compatibility with CPython it can also be a + a string with space-separated field named (but this is less efficient). + Example of use:: + + from collections import namedtuple + + MyTuple = namedtuple("MyTuple", ("id", "name")) + t1 = MyTuple(1, "foo") + t2 = MyTuple(2, "bar") + print(t1.name) + assert t2.name == t2[1] + """ + ... + +class OrderedDict(Dict[_KT, _VT], Generic[_KT, _VT]): + """ + ``dict`` type subclass which remembers and preserves the order of keys + added. When ordered dict is iterated over, keys/items are returned in + the order they were added:: + + from collections import OrderedDict + + # To make benefit of ordered keys, OrderedDict should be initialized + # from sequence of (key, value) pairs. + d = OrderedDict([("z", 1), ("a", 2)]) + # More items can be added as usual + d["w"] = 5 + d["b"] = 3 + for k, v in d.items(): + print(k, v) + + Output:: + + z 1 + a 2 + w 5 + b 3 + """ + def popitem(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def values(self, *args, **kwargs) -> Incomplete: ... + def setdefault(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def keys(self, *args, **kwargs) -> Incomplete: ... + def get(self, *args, **kwargs) -> Incomplete: ... + def items(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromkeys(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *args, **kwargs) -> None: ... + +class deque: + """ + Minimal implementation of a deque that implements a FIFO buffer. + """ + def pop(self) -> Incomplete: + """ + Remove and return an item from the right side of the deque. + Raises ``IndexError`` if no items are present. + """ + ... + def appendleft(self, x: _T, /) -> Incomplete: + """ + Add *x* to the left side of the deque. + Raises ``IndexError`` if overflow checking is enabled and there is + no more room in the queue. + """ + ... + def popleft(self) -> Any: + """ + Remove and return an item from the left side of the deque. + Raises ``IndexError`` if no items are present. + """ + ... + def extend(self, iterable: Iterable[_T], /) -> Incomplete: + """ + Extend the deque by appending all the items from *iterable* to + the right of the deque. + Raises ``IndexError`` if overflow checking is enabled and there is + no more room in the deque. + """ + ... + def append(self, x: _T, /) -> None: + """ + Add *x* to the right side of the deque. + Raises ``IndexError`` if overflow checking is enabled and there is + no more room in the queue. + """ + ... + def __init__(self, iterable: tuple[Any], maxlen: int, flags: int = 0, /) -> None: + """ + Deques (double-ended queues) are a list-like container that support O(1) + appends and pops from either side of the deque. New deques are created + using the following arguments: + + - *iterable* must be the empty tuple, and the new deque is created empty. + + - *maxlen* must be specified and the deque will be bounded to this + maximum length. Once the deque is full, any new items added will + discard items from the opposite end. + + - The optional *flags* can be 1 to check for overflow when adding items. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ucryptolib.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ucryptolib.pyi new file mode 100644 index 000000000..6b8b56a68 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ucryptolib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to cryptolib +from cryptolib import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uctypes.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uctypes.pyi new file mode 100644 index 000000000..a74802960 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uctypes.pyi @@ -0,0 +1,164 @@ +""" +Access binary data in a structured way. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/uctypes.html + +This module implements "foreign data interface" for MicroPython. The idea +behind it is similar to CPython's ``ctypes`` modules, but the actual API is +different, streamlined and optimized for small size. The basic idea of the +module is to define data structure layout with about the same power as the +C language allows, and then access it using familiar dot-syntax to reference +sub-fields. + +--- +Module: 'uctypes' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Tuple, Any, Final, Generator +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +VOID: Final[int] = 0 +"""\ +``VOID`` is an alias for ``UINT8``, and is provided to conveniently define +C's void pointers: ``(uctypes.PTR, uctypes.VOID)``. +""" +NATIVE: Final[int] = 2 +"""\ +Layout type for a native structure - with data endianness and alignment +conforming to the ABI of the system on which MicroPython runs. +""" +PTR: Final[int] = 536870912 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +SHORT: Final[int] = 402653184 +LONGLONG: Final[int] = 939524096 +INT8: Final[int] = 134217728 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +LITTLE_ENDIAN: Final[int] = 0 +"""\ +Layout type for a little-endian packed structure. (Packed means that every +field occupies exactly as many bytes as defined in the descriptor, i.e. +the alignment is 1). +""" +LONG: Final[int] = 671088640 +UINT: Final[int] = 536870912 +ULONG: Final[int] = 536870912 +ULONGLONG: Final[int] = 805306368 +USHORT: Final[int] = 268435456 +UINT8: Final[int] = 0 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT16: Final[int] = 268435456 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT32: Final[int] = 536870912 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT64: Final[int] = 805306368 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT64: Final[int] = 939524096 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +BFUINT16: Final[int] = -805306368 +BFUINT32: Final[int] = -536870912 +BFUINT8: Final[int] = -1073741824 +BFINT8: Final[int] = -939524096 +ARRAY: Final[int] = -1073741824 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +BFINT16: Final[int] = -671088640 +BFINT32: Final[int] = -402653184 +BF_LEN: Final[int] = 22 +INT: Final[int] = 671088640 +INT16: Final[int] = 402653184 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT32: Final[int] = 671088640 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +FLOAT64: Final[int] = -134217728 +"""Floating-point types for structure descriptors.""" +BF_POS: Final[int] = 17 +BIG_ENDIAN: Final[int] = 1 +"""Layout type for a big-endian packed structure.""" +FLOAT32: Final[int] = -268435456 +"""Floating-point types for structure descriptors.""" +_property: TypeAlias = Incomplete +_descriptor: TypeAlias = Tuple | Dict + +def sizeof(struct: struct | _descriptor | dict, layout_type: int = NATIVE, /) -> int: + """ + Return size of data structure in bytes. The *struct* argument can be + either a structure class or a specific instantiated structure object + (or its aggregate field). + """ + ... + +def bytes_at(addr: int, size: int, /) -> bytes: + """ + Capture memory at the given address and size as bytes object. As bytes + object is immutable, memory is actually duplicated and copied into + bytes object, so if memory contents change later, created object + retains original value. + """ + ... + +def bytearray_at(addr: int, size: int, /) -> bytearray: + """ + Capture memory at the given address and size as bytearray object. + Unlike bytes_at() function above, memory is captured by reference, + so it can be both written too, and you will access current value + at the given memory address. + """ + ... + +def addressof(obj: AnyReadableBuf, /) -> int: + """ + Return address of an object. Argument should be bytes, bytearray or + other object supporting buffer protocol (and address of this buffer + is what actually returned). + """ + ... + +class struct: + """ + Module contents + --------------- + """ + def __init__(self, addr: int | struct, descriptor: _descriptor, layout_type: int = NATIVE, /) -> None: + """ + Instantiate a "foreign data structure" object based on structure address in + memory, descriptor (encoded as a dictionary), and layout type (see below). + """ + ... + @mp_available() # force push + def __getattr__(self, a): ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uerrno.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uerrno.pyi new file mode 100644 index 000000000..8d34ba6b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uerrno.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to errno +from errno import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uhashlib.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uhashlib.pyi new file mode 100644 index 000000000..8b4b7bc77 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uhashlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to hashlib +from hashlib import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uheapq.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uheapq.pyi new file mode 100644 index 000000000..71c066fcf --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uheapq.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to heapq +from heapq import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uio.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uio.pyi new file mode 100644 index 000000000..514a4f945 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to io +from io import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ujson.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ujson.pyi new file mode 100644 index 000000000..0de669254 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ujson.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to json +from json import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/umachine.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/umachine.pyi new file mode 100644 index 000000000..e1fdb35a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/umachine.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to machine +from machine import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uos.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uos.pyi new file mode 100644 index 000000000..8c99e764b --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uos.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to os +from os import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uplatform.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uplatform.pyi new file mode 100644 index 000000000..22ad247bf --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uplatform.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to platform +from platform import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/urandom.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/urandom.pyi new file mode 100644 index 000000000..b912f0793 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/urandom.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to random +from random import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ure.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ure.pyi new file mode 100644 index 000000000..dbe8b6a52 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ure.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to re +from re import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/urequests.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/urequests.pyi new file mode 100644 index 000000000..3ef9fce15 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/urequests.pyi @@ -0,0 +1,25 @@ +""" +Module: 'urequests' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def head(*args, **kwargs) -> Incomplete: ... +def patch(*args, **kwargs) -> Incomplete: ... +def post(*args, **kwargs) -> Incomplete: ... +def put(*args, **kwargs) -> Incomplete: ... +def request(*args, **kwargs) -> Incomplete: ... +def delete(*args, **kwargs) -> Incomplete: ... +def get(*args, **kwargs) -> Incomplete: ... + +class Response: + def json(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + + content: Incomplete ## = + text: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uselect.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uselect.pyi new file mode 100644 index 000000000..a543041c4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uselect.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to select +from select import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/usocket.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/usocket.pyi new file mode 100644 index 000000000..140590c29 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/usocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to socket +from socket import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ussl.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ussl.pyi new file mode 100644 index 000000000..3115761c4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ussl.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to ssl +from ssl import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ustruct.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ustruct.pyi new file mode 100644 index 000000000..0f7fb657a --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/ustruct.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to struct +from struct import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/usys.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/usys.pyi new file mode 100644 index 000000000..298d7a8ac --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/usys.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to sys +from sys import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/utime.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/utime.pyi new file mode 100644 index 000000000..1f972a5b6 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/utime.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to time +from time import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uwebsocket.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uwebsocket.pyi new file mode 100644 index 000000000..afa801ba2 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uwebsocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to websocket +from websocket import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uzlib.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uzlib.pyi new file mode 100644 index 000000000..5fad9a23c --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/uzlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to zlib +from zlib import * diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/vfs.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/vfs.pyi new file mode 100644 index 000000000..97e4941f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/vfs.pyi @@ -0,0 +1,240 @@ +""" +Virtual filesystem control. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/vfs.html + +The ``vfs`` module contains functions for creating filesystem objects and +mounting/unmounting them in the Virtual Filesystem. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +--- +Module: 'vfs' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _BlockDeviceProtocol +from abc import ABC, abstractmethod +from typing import List, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def umount(mount_point: Incomplete) -> Incomplete: + """ + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + """ + ... + +@overload +def mount(fsobj, mount_point: str, *, readonly: bool = False) -> None: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +@overload +def mount() -> List[tuple[Incomplete, str]]: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +class VfsLfs2: + """ + Create a filesystem object that uses the `littlefs v2 filesystem format`_. + Storage of the littlefs filesystem is provided by *block_dev*, which must + support the :ref:`extended interface `. + Objects created by this constructor can be mounted using :func:`mount`. + + The *mtime* argument enables modification timestamps for files, stored using + littlefs attributes. This option can be disabled or enabled differently each + mount time and timestamps will only be added or updated if *mtime* is enabled, + otherwise the timestamps will remain untouched. Littlefs v2 filesystems without + timestamps will work without reformatting and timestamps will be added + transparently to existing files once they are opened for writing. When *mtime* + is enabled `os.stat` on files without timestamps will return 0 for the timestamp. + + See :ref:`filesystem` for more information. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32) -> None: + """ + Build a Lfs2 filesystem on *block_dev*. + + ``Note:`` There are reports of littlefs v2 failing in certain situations, + for details see `littlefs issue 295`_. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32, mtime=True) -> None: ... + +class VfsFat: + """ + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev) -> None: + """ + Build a FAT filesystem on *block_dev*. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev) -> None: ... + +class AbstractBlockDev: + # + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: ... + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + ... + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + ... + + @abstractmethod + @overload + def ioctl(self, op: int, arg) -> int | None: ... + # + @abstractmethod + @overload + def ioctl(self, op: int) -> int | None: + """ + Control the block device and query its parameters. The operation to + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 5 -- get the number of bytes in a block, should return an integer, + or ``None`` in which case the default value of 512 is used + (*arg* is unused) + - 6 -- erase a block, *arg* is the block number to erase + + As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs + ``ioctl(6, ...)`` must also be intercepted. The need for others is + hardware dependent. + + Prior to any call to ``writeblocks(block, ...)`` littlefs issues + ``ioctl(6, block)``. This enables a device driver to erase the block + prior to a write if the hardware requires it. Alternatively a driver + might intercept ``ioctl(6, block)`` and return 0 (success). In this case + the driver assumes responsibility for detecting the need for erasure. + + Unless otherwise stated ``ioctl(op, arg)`` can return ``None``. + Consequently an implementation can ignore unused values of ``op``. Where + ``op`` is intercepted, the return value for operations 4 and 5 are as + detailed above. Other operations should return 0 on success and non-zero + for failure, with the value returned being an ``OSError`` errno code. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/websocket.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/websocket.pyi new file mode 100644 index 000000000..62bf8e79b --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged/websocket.pyi @@ -0,0 +1,17 @@ +""" +Module: 'websocket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class websocket: + def readline(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_asyncio.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_asyncio.pyi new file mode 100644 index 000000000..c326137ff --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_asyncio.pyi @@ -0,0 +1,18 @@ +""" +Module: '_asyncio' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class TaskQueue: + def push(self, *args, **kwargs) -> Incomplete: ... + def peek(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Task: + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_onewire.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_onewire.pyi new file mode 100644 index 000000000..2e9c634f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_onewire.pyi @@ -0,0 +1,15 @@ +""" +Module: '_onewire' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def reset(*args, **kwargs) -> Incomplete: ... +def writebyte(*args, **kwargs) -> Incomplete: ... +def writebit(*args, **kwargs) -> Incomplete: ... +def crc8(*args, **kwargs) -> Incomplete: ... +def readbyte(*args, **kwargs) -> Incomplete: ... +def readbit(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/array.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/array.pyi new file mode 100644 index 000000000..c305002b6 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/array.pyi @@ -0,0 +1,13 @@ +""" +Module: 'array' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class array: + def extend(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/__init__.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/__init__.pyi new file mode 100644 index 000000000..6b112c9bd --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/__init__.pyi @@ -0,0 +1,278 @@ +""" +Module: 'asyncio.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +_attrs: dict = {} +def current_task(*args, **kwargs) -> Incomplete: + ... + +def get_event_loop(*args, **kwargs) -> Incomplete: + ... + +def create_task(*args, **kwargs) -> Incomplete: + ... + +def ticks_diff(*args, **kwargs) -> Incomplete: + ... + +def new_event_loop(*args, **kwargs) -> Incomplete: + ... + +def ticks(*args, **kwargs) -> Incomplete: + ... + +def run_until_complete(*args, **kwargs) -> Incomplete: + ... + +def run(*args, **kwargs) -> Incomplete: + ... + +def wait_for_ms(*args, **kwargs) -> Incomplete: + ... + +def sleep_ms(*args, **kwargs) -> Incomplete: + ... + +def ticks_add(*args, **kwargs) -> Incomplete: + ... + +def sleep(*args, **kwargs) -> Incomplete: + ... + + +class TaskQueue(): + def push(self, *args, **kwargs) -> Incomplete: + ... + + def peek(self, *args, **kwargs) -> Incomplete: + ... + + def remove(self, *args, **kwargs) -> Incomplete: + ... + + def pop(self, *args, **kwargs) -> Incomplete: + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + +def open_connection(*args, **kwargs) -> Generator: ## = + ... + +cur_task: Incomplete ## = None +def gather(*args, **kwargs) -> Generator: ## = + ... + + +class Task(): + def __init__(self, *argv, **kwargs) -> None: + ... + +def wait_for(*args, **kwargs) -> Generator: ## = + ... + + +class CancelledError(Exception): + ... +def start_server(*args, **kwargs) -> Generator: ## = + ... + + +class Lock(): + def locked(self, *args, **kwargs) -> Incomplete: + ... + + def release(self, *args, **kwargs) -> Incomplete: + ... + + def acquire(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class StreamWriter(): + def write(self, *args, **kwargs) -> Incomplete: + ... + + def get_extra_info(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def awritestr(*args, **kwargs) -> Generator: ## = + ... + + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + + def drain(*args, **kwargs) -> Generator: ## = + ... + + def readexactly(*args, **kwargs) -> Generator: ## = + ... + + def readinto(*args, **kwargs) -> Generator: ## = + ... + + def read(*args, **kwargs) -> Generator: ## = + ... + + def awrite(*args, **kwargs) -> Generator: ## = + ... + + def readline(*args, **kwargs) -> Generator: ## = + ... + + def aclose(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class StreamReader(): + def write(self, *args, **kwargs) -> Incomplete: + ... + + def get_extra_info(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def awritestr(*args, **kwargs) -> Generator: ## = + ... + + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + + def drain(*args, **kwargs) -> Generator: ## = + ... + + def readexactly(*args, **kwargs) -> Generator: ## = + ... + + def readinto(*args, **kwargs) -> Generator: ## = + ... + + def read(*args, **kwargs) -> Generator: ## = + ... + + def awrite(*args, **kwargs) -> Generator: ## = + ... + + def readline(*args, **kwargs) -> Generator: ## = + ... + + def aclose(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class SingletonGenerator(): + def __init__(self, *argv, **kwargs) -> None: + ... + + +class Loop(): + def get_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def default_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def set_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def run_forever(self, *args, **kwargs) -> Incomplete: + ... + + def run_until_complete(self, *args, **kwargs) -> Incomplete: + ... + + def stop(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def create_task(self, *args, **kwargs) -> Incomplete: + ... + + def call_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + _exc_handler: Incomplete ## = None + def __init__(self, *argv, **kwargs) -> None: + ... + + +class Event(): + def set(self, *args, **kwargs) -> Incomplete: + ... + + def is_set(self, *args, **kwargs) -> Incomplete: + ... + + def clear(self, *args, **kwargs) -> Incomplete: + ... + + def wait(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class ThreadSafeFlag(): + def set(self, *args, **kwargs) -> Incomplete: + ... + + def ioctl(self, *args, **kwargs) -> Incomplete: + ... + + def clear(self, *args, **kwargs) -> Incomplete: + ... + + def wait(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class IOQueue(): + def queue_read(self, *args, **kwargs) -> Incomplete: + ... + + def wait_io_event(self, *args, **kwargs) -> Incomplete: + ... + + def queue_write(self, *args, **kwargs) -> Incomplete: + ... + + def remove(self, *args, **kwargs) -> Incomplete: + ... + + def _enqueue(self, *args, **kwargs) -> Incomplete: + ... + + def _dequeue(self, *args, **kwargs) -> Incomplete: + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class TimeoutError(Exception): + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/core.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/core.pyi new file mode 100644 index 000000000..f0623365f --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/core.pyi @@ -0,0 +1,73 @@ +""" +Module: 'asyncio.core' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +_exc_context: dict = {} + +def ticks(*args, **kwargs) -> Incomplete: ... +def create_task(*args, **kwargs) -> Incomplete: ... +def _promote_to_task(*args, **kwargs) -> Incomplete: ... +def ticks_diff(*args, **kwargs) -> Incomplete: ... +def run(*args, **kwargs) -> Incomplete: ... +def run_until_complete(*args, **kwargs) -> Incomplete: ... +def current_task(*args, **kwargs) -> Incomplete: ... +def new_event_loop(*args, **kwargs) -> Incomplete: ... +def get_event_loop(*args, **kwargs) -> Incomplete: ... +def sleep_ms(*args, **kwargs) -> Incomplete: ... +def ticks_add(*args, **kwargs) -> Incomplete: ... +def sleep(*args, **kwargs) -> Incomplete: ... + +cur_task: Incomplete ## = None +_task_queue: Incomplete ## = + +class Loop: + def get_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def default_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def set_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def run_forever(self, *args, **kwargs) -> Incomplete: ... + def run_until_complete(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def create_task(self, *args, **kwargs) -> Incomplete: ... + def call_exception_handler(self, *args, **kwargs) -> Incomplete: ... + + _exc_handler: Incomplete ## = None + def __init__(self, *argv, **kwargs) -> None: ... + +class CancelledError(Exception): ... + +class TaskQueue: + def push(self, *args, **kwargs) -> Incomplete: ... + def peek(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Task: + def __init__(self, *argv, **kwargs) -> None: ... + +class TimeoutError(Exception): ... + +class IOQueue: + def queue_read(self, *args, **kwargs) -> Incomplete: ... + def wait_io_event(self, *args, **kwargs) -> Incomplete: ... + def queue_write(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def _enqueue(self, *args, **kwargs) -> Incomplete: ... + def _dequeue(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SingletonGenerator: + def __init__(self, *argv, **kwargs) -> None: ... + +def _stopper(*args, **kwargs) -> Generator: ## = + ... + +_stop_task: Incomplete ## = None +_io_queue: Incomplete ## = diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/event.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/event.pyi new file mode 100644 index 000000000..fbc254140 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/event.pyi @@ -0,0 +1,25 @@ +""" +Module: 'asyncio.event' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +class ThreadSafeFlag: + def set(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def wait(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Event: + def set(self, *args, **kwargs) -> Incomplete: ... + def is_set(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def wait(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/funcs.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/funcs.pyi new file mode 100644 index 000000000..c8777cc53 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/funcs.pyi @@ -0,0 +1,22 @@ +""" +Module: 'asyncio.funcs' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +def wait_for_ms(*args, **kwargs) -> Incomplete: ... +def gather(*args, **kwargs) -> Generator: ## = + ... +def wait_for(*args, **kwargs) -> Generator: ## = + ... + +class _Remove: + def remove(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +def _run(*args, **kwargs) -> Generator: ## = + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/lock.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/lock.pyi new file mode 100644 index 000000000..2d17cc567 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/lock.pyi @@ -0,0 +1,16 @@ +""" +Module: 'asyncio.lock' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +class Lock: + def locked(self, *args, **kwargs) -> Incomplete: ... + def release(self, *args, **kwargs) -> Incomplete: ... + def acquire(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/stream.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/stream.pyi new file mode 100644 index 000000000..eff3fa5c4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/stream.pyi @@ -0,0 +1,96 @@ +""" +Module: 'asyncio.stream' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +def stream_awrite(*args, **kwargs) -> Generator: ## = + ... +def open_connection(*args, **kwargs) -> Generator: ## = + ... +def start_server(*args, **kwargs) -> Generator: ## = + ... + +class StreamWriter: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Server: + def close(self, *args, **kwargs) -> Incomplete: ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def _serve(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Stream: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class StreamReader: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/binascii.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/binascii.pyi new file mode 100644 index 000000000..7218742da --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/binascii.pyi @@ -0,0 +1,14 @@ +""" +Module: 'binascii' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def crc32(*args, **kwargs) -> Incomplete: ... +def hexlify(*args, **kwargs) -> Incomplete: ... +def unhexlify(*args, **kwargs) -> Incomplete: ... +def b2a_base64(*args, **kwargs) -> Incomplete: ... +def a2b_base64(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/builtins.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/builtins.pyi new file mode 100644 index 000000000..5dc4ab44d --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/builtins.pyi @@ -0,0 +1,305 @@ +""" +Module: 'builtins' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def any(*args, **kwargs) -> Incomplete: ... +def all(*args, **kwargs) -> Incomplete: ... +def len(*args, **kwargs) -> Incomplete: ... +def id(*args, **kwargs) -> Incomplete: ... +def sum(*args, **kwargs) -> Incomplete: ... +def issubclass(*args, **kwargs) -> Incomplete: ... +def iter(*args, **kwargs) -> Incomplete: ... +def abs(*args, **kwargs) -> Incomplete: ... +def isinstance(*args, **kwargs) -> Incomplete: ... +def setattr(*args, **kwargs) -> Incomplete: ... +def eval(*args, **kwargs) -> Incomplete: ... +def divmod(*args, **kwargs) -> Incomplete: ... +def hash(*args, **kwargs) -> Incomplete: ... +def exec(*args, **kwargs) -> Incomplete: ... +def getattr(*args, **kwargs) -> Incomplete: ... +def chr(*args, **kwargs) -> Incomplete: ... +def callable(*args, **kwargs) -> Incomplete: ... +def dir(*args, **kwargs) -> Incomplete: ... +def hasattr(*args, **kwargs) -> Incomplete: ... +def sorted(*args, **kwargs) -> Incomplete: ... +def globals(*args, **kwargs) -> Incomplete: ... +def max(*args, **kwargs) -> Incomplete: ... +def input(*args, **kwargs) -> Incomplete: ... +def hex(*args, **kwargs) -> Incomplete: ... +def help(*args, **kwargs) -> Incomplete: ... +def open(*args, **kwargs) -> Incomplete: ... +def ord(*args, **kwargs) -> Incomplete: ... +def pow(*args, **kwargs) -> Incomplete: ... +def oct(*args, **kwargs) -> Incomplete: ... +def min(*args, **kwargs) -> Incomplete: ... +def print(*args, **kwargs) -> Incomplete: ... +def repr(*args, **kwargs) -> Incomplete: ... +def locals(*args, **kwargs) -> Incomplete: ... +def compile(*args, **kwargs) -> Incomplete: ... +def bin(*args, **kwargs) -> Incomplete: ... +def execfile(*args, **kwargs) -> Incomplete: ... +def next(*args, **kwargs) -> Incomplete: ... +def delattr(*args, **kwargs) -> Incomplete: ... +def round(*args, **kwargs) -> Incomplete: ... + +NotImplemented: Incomplete ## = NotImplemented +Ellipsis: Incomplete ## = Ellipsis + +class set: + def discard(self, *args, **kwargs) -> Incomplete: ... + def isdisjoint(self, *args, **kwargs) -> Incomplete: ... + def intersection_update(self, *args, **kwargs) -> Incomplete: ... + def intersection(self, *args, **kwargs) -> Incomplete: ... + def issubset(self, *args, **kwargs) -> Incomplete: ... + def symmetric_difference_update(self, *args, **kwargs) -> Incomplete: ... + def symmetric_difference(self, *args, **kwargs) -> Incomplete: ... + def issuperset(self, *args, **kwargs) -> Incomplete: ... + def union(self, *args, **kwargs) -> Incomplete: ... + def difference_update(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def difference(self, *args, **kwargs) -> Incomplete: ... + def add(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class slice: + def __init__(self, *argv, **kwargs) -> None: ... + +class complex: + def __init__(self, *argv, **kwargs) -> None: ... + +class float: + def __init__(self, *argv, **kwargs) -> None: ... + +class filter: + def __init__(self, *argv, **kwargs) -> None: ... + +class enumerate: + def __init__(self, *argv, **kwargs) -> None: ... + +class frozenset: + def union(self, *args, **kwargs) -> Incomplete: ... + def issubset(self, *args, **kwargs) -> Incomplete: ... + def issuperset(self, *args, **kwargs) -> Incomplete: ... + def symmetric_difference(self, *args, **kwargs) -> Incomplete: ... + def isdisjoint(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def difference(self, *args, **kwargs) -> Incomplete: ... + def intersection(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class reversed: + def __init__(self, *argv, **kwargs) -> None: ... + +class property: + def getter(self, *args, **kwargs) -> Incomplete: ... + def setter(self, *args, **kwargs) -> Incomplete: ... + def deleter(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class memoryview: + def hex(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class ViperTypeError(Exception): ... + +class tuple: + def index(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class super: + def __init__(self, *argv, **kwargs) -> None: ... + +class str: + def rstrip(self, *args, **kwargs) -> Incomplete: ... + def startswith(self, *args, **kwargs) -> Incomplete: ... + def split(self, *args, **kwargs) -> Incomplete: ... + def rfind(self, *args, **kwargs) -> Incomplete: ... + def rsplit(self, *args, **kwargs) -> Incomplete: ... + def rindex(self, *args, **kwargs) -> Incomplete: ... + def replace(self, *args, **kwargs) -> Incomplete: ... + def partition(self, *args, **kwargs) -> Incomplete: ... + def strip(self, *args, **kwargs) -> Incomplete: ... + def rpartition(self, *args, **kwargs) -> Incomplete: ... + def upper(self, *args, **kwargs) -> Incomplete: ... + def encode(self, *args, **kwargs) -> Incomplete: ... + def center(self, *args, **kwargs) -> Incomplete: ... + def splitlines(self, *args, **kwargs) -> Incomplete: ... + def format(self, *args, **kwargs) -> Incomplete: ... + def isalpha(self, *args, **kwargs) -> Incomplete: ... + def index(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def find(self, *args, **kwargs) -> Incomplete: ... + def endswith(self, *args, **kwargs) -> Incomplete: ... + def lstrip(self, *args, **kwargs) -> Incomplete: ... + def join(self, *args, **kwargs) -> Incomplete: ... + def isdigit(self, *args, **kwargs) -> Incomplete: ... + def lower(self, *args, **kwargs) -> Incomplete: ... + def islower(self, *args, **kwargs) -> Incomplete: ... + def isupper(self, *args, **kwargs) -> Incomplete: ... + def isspace(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class type: + def __init__(self, *argv, **kwargs) -> None: ... + +class UnicodeError(Exception): ... + +class StopAsyncIteration: + def __init__(self, *argv, **kwargs) -> None: ... + +class zip: + def __init__(self, *argv, **kwargs) -> None: ... + +class IndentationError(Exception): ... +class KeyboardInterrupt(Exception): ... +class KeyError(Exception): ... +class IndexError(Exception): ... +class LookupError(Exception): ... +class NotImplementedError(Exception): ... +class NameError(Exception): ... +class MemoryError(Exception): ... +class OSError(Exception): ... +class ImportError(Exception): ... +class AttributeError(Exception): ... +class AssertionError(Exception): ... +class ArithmeticError(Exception): ... + +class GeneratorExit: + def __init__(self, *argv, **kwargs) -> None: ... + +class EOFError(Exception): ... + +class range: + def __init__(self, *argv, **kwargs) -> None: ... + +class bytearray: + def rstrip(self, *args, **kwargs) -> Incomplete: ... + def rsplit(self, *args, **kwargs) -> Incomplete: ... + def split(self, *args, **kwargs) -> Incomplete: ... + def startswith(self, *args, **kwargs) -> Incomplete: ... + def replace(self, *args, **kwargs) -> Incomplete: ... + def rindex(self, *args, **kwargs) -> Incomplete: ... + def rfind(self, *args, **kwargs) -> Incomplete: ... + def splitlines(self, *args, **kwargs) -> Incomplete: ... + def partition(self, *args, **kwargs) -> Incomplete: ... + def hex(self, *args, **kwargs) -> Incomplete: ... + def rpartition(self, *args, **kwargs) -> Incomplete: ... + def strip(self, *args, **kwargs) -> Incomplete: ... + def upper(self, *args, **kwargs) -> Incomplete: ... + def decode(self, *args, **kwargs) -> Incomplete: ... + def center(self, *args, **kwargs) -> Incomplete: ... + def find(self, *args, **kwargs) -> Incomplete: ... + def extend(self, *args, **kwargs) -> Incomplete: ... + def format(self, *args, **kwargs) -> Incomplete: ... + def index(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def endswith(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def lstrip(self, *args, **kwargs) -> Incomplete: ... + def isalpha(self, *args, **kwargs) -> Incomplete: ... + def isupper(self, *args, **kwargs) -> Incomplete: ... + def join(self, *args, **kwargs) -> Incomplete: ... + def lower(self, *args, **kwargs) -> Incomplete: ... + def islower(self, *args, **kwargs) -> Incomplete: ... + def isdigit(self, *args, **kwargs) -> Incomplete: ... + def isspace(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromhex(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class dict: + def popitem(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def values(self, *args, **kwargs) -> Incomplete: ... + def setdefault(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def keys(self, *args, **kwargs) -> Incomplete: ... + def get(self, *args, **kwargs) -> Incomplete: ... + def items(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromkeys(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class bytes: + def split(self, *args, **kwargs) -> Incomplete: ... + def rstrip(self, *args, **kwargs) -> Incomplete: ... + def startswith(self, *args, **kwargs) -> Incomplete: ... + def splitlines(self, *args, **kwargs) -> Incomplete: ... + def rfind(self, *args, **kwargs) -> Incomplete: ... + def rsplit(self, *args, **kwargs) -> Incomplete: ... + def rindex(self, *args, **kwargs) -> Incomplete: ... + def partition(self, *args, **kwargs) -> Incomplete: ... + def hex(self, *args, **kwargs) -> Incomplete: ... + def rpartition(self, *args, **kwargs) -> Incomplete: ... + def strip(self, *args, **kwargs) -> Incomplete: ... + def upper(self, *args, **kwargs) -> Incomplete: ... + def decode(self, *args, **kwargs) -> Incomplete: ... + def center(self, *args, **kwargs) -> Incomplete: ... + def index(self, *args, **kwargs) -> Incomplete: ... + def format(self, *args, **kwargs) -> Incomplete: ... + def isalpha(self, *args, **kwargs) -> Incomplete: ... + def replace(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def find(self, *args, **kwargs) -> Incomplete: ... + def endswith(self, *args, **kwargs) -> Incomplete: ... + def isdigit(self, *args, **kwargs) -> Incomplete: ... + def join(self, *args, **kwargs) -> Incomplete: ... + def lower(self, *args, **kwargs) -> Incomplete: ... + def lstrip(self, *args, **kwargs) -> Incomplete: ... + def isspace(self, *args, **kwargs) -> Incomplete: ... + def islower(self, *args, **kwargs) -> Incomplete: ... + def isupper(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromhex(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class int: + def to_bytes(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def from_bytes(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class object: + def __init__(self, *argv, **kwargs) -> None: ... + +class map: + def __init__(self, *argv, **kwargs) -> None: ... + +class list: + def pop(self, *args, **kwargs) -> Incomplete: ... + def insert(self, *args, **kwargs) -> Incomplete: ... + def index(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def reverse(self, *args, **kwargs) -> Incomplete: ... + def sort(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def extend(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class OverflowError(Exception): ... + +class bool: + def __init__(self, *argv, **kwargs) -> None: ... + +class SyntaxError(Exception): ... +class StopIteration(Exception): ... +class RuntimeError(Exception): ... +class SystemExit(Exception): ... +class ZeroDivisionError(Exception): ... +class ValueError(Exception): ... +class TypeError(Exception): ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cmath.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cmath.pyi new file mode 100644 index 000000000..5e29dcf02 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cmath.pyi @@ -0,0 +1,21 @@ +""" +Module: 'cmath' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +e: float = 2.718281828459045 +pi: float = 3.141592653589793 + +def polar(*args, **kwargs) -> Incomplete: ... +def sqrt(*args, **kwargs) -> Incomplete: ... +def rect(*args, **kwargs) -> Incomplete: ... +def sin(*args, **kwargs) -> Incomplete: ... +def exp(*args, **kwargs) -> Incomplete: ... +def cos(*args, **kwargs) -> Incomplete: ... +def phase(*args, **kwargs) -> Incomplete: ... +def log(*args, **kwargs) -> Incomplete: ... +def log10(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/collections.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/collections.pyi new file mode 100644 index 000000000..d922ab2ce --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/collections.pyi @@ -0,0 +1,33 @@ +""" +Module: 'collections' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def namedtuple(*args, **kwargs) -> Incomplete: ... + +class OrderedDict: + def popitem(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def values(self, *args, **kwargs) -> Incomplete: ... + def setdefault(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def keys(self, *args, **kwargs) -> Incomplete: ... + def get(self, *args, **kwargs) -> Incomplete: ... + def items(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromkeys(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class deque: + def pop(self, *args, **kwargs) -> Incomplete: ... + def appendleft(self, *args, **kwargs) -> Incomplete: ... + def popleft(self, *args, **kwargs) -> Incomplete: ... + def extend(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cryptolib.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cryptolib.pyi new file mode 100644 index 000000000..e3818a7f4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cryptolib.pyi @@ -0,0 +1,13 @@ +""" +Module: 'cryptolib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class aes: + def encrypt(self, *args, **kwargs) -> Incomplete: ... + def decrypt(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/deflate.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/deflate.pyi new file mode 100644 index 000000000..b3465d1b1 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/deflate.pyi @@ -0,0 +1,22 @@ +""" +Module: 'deflate' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +GZIP: Final[int] = 3 +RAW: Final[int] = 1 +ZLIB: Final[int] = 2 +AUTO: Final[int] = 0 + +class DeflateIO: + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/dht.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/dht.pyi new file mode 100644 index 000000000..3a5da285f --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/dht.pyi @@ -0,0 +1,26 @@ +""" +Module: 'dht' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def dht_readinto(*args, **kwargs) -> Incomplete: ... + +class DHTBase: + def measure(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT22: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT11: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ds18x20.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ds18x20.pyi new file mode 100644 index 000000000..cf3ac9fc2 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ds18x20.pyi @@ -0,0 +1,18 @@ +""" +Module: 'ds18x20' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def const(*args, **kwargs) -> Incomplete: ... + +class DS18X20: + def read_scratch(self, *args, **kwargs) -> Incomplete: ... + def read_temp(self, *args, **kwargs) -> Incomplete: ... + def write_scratch(self, *args, **kwargs) -> Incomplete: ... + def convert_temp(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/errno.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/errno.pyi new file mode 100644 index 000000000..a4c0dba91 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/errno.pyi @@ -0,0 +1,33 @@ +""" +Module: 'errno' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +ENOBUFS: Final[int] = 105 +ENODEV: Final[int] = 19 +ENOENT: Final[int] = 2 +EISDIR: Final[int] = 21 +EIO: Final[int] = 5 +EINVAL: Final[int] = 22 +EPERM: Final[int] = 1 +ETIMEDOUT: Final[int] = 116 +ENOMEM: Final[int] = 12 +EOPNOTSUPP: Final[int] = 95 +ENOTCONN: Final[int] = 128 +errorcode: dict = {} +EAGAIN: Final[int] = 11 +EALREADY: Final[int] = 120 +EBADF: Final[int] = 9 +EADDRINUSE: Final[int] = 112 +EACCES: Final[int] = 13 +EINPROGRESS: Final[int] = 119 +EEXIST: Final[int] = 17 +EHOSTUNREACH: Final[int] = 118 +ECONNABORTED: Final[int] = 113 +ECONNRESET: Final[int] = 104 +ECONNREFUSED: Final[int] = 111 diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/framebuf.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/framebuf.pyi new file mode 100644 index 000000000..f31234615 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/framebuf.pyi @@ -0,0 +1,35 @@ +""" +Module: 'framebuf' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +MONO_HMSB: Final[int] = 4 +MONO_HLSB: Final[int] = 3 +RGB565: Final[int] = 1 +MONO_VLSB: Final[int] = 0 +MVLSB: Final[int] = 0 +GS2_HMSB: Final[int] = 5 +GS8: Final[int] = 6 +GS4_HMSB: Final[int] = 2 + +def FrameBuffer1(*args, **kwargs) -> Incomplete: ... + +class FrameBuffer: + def poly(self, *args, **kwargs) -> Incomplete: ... + def vline(self, *args, **kwargs) -> Incomplete: ... + def pixel(self, *args, **kwargs) -> Incomplete: ... + def text(self, *args, **kwargs) -> Incomplete: ... + def rect(self, *args, **kwargs) -> Incomplete: ... + def scroll(self, *args, **kwargs) -> Incomplete: ... + def ellipse(self, *args, **kwargs) -> Incomplete: ... + def line(self, *args, **kwargs) -> Incomplete: ... + def blit(self, *args, **kwargs) -> Incomplete: ... + def hline(self, *args, **kwargs) -> Incomplete: ... + def fill(self, *args, **kwargs) -> Incomplete: ... + def fill_rect(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/gc.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/gc.pyi new file mode 100644 index 000000000..6ca7fb44e --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/gc.pyi @@ -0,0 +1,16 @@ +""" +Module: 'gc' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def mem_alloc(*args, **kwargs) -> Incomplete: ... +def isenabled(*args, **kwargs) -> Incomplete: ... +def mem_free(*args, **kwargs) -> Incomplete: ... +def threshold(*args, **kwargs) -> Incomplete: ... +def collect(*args, **kwargs) -> Incomplete: ... +def enable(*args, **kwargs) -> Incomplete: ... +def disable(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/hashlib.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/hashlib.pyi new file mode 100644 index 000000000..64e404b69 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/hashlib.pyi @@ -0,0 +1,23 @@ +""" +Module: 'hashlib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class sha1: + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class sha256: + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class md5: + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/heapq.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/heapq.pyi new file mode 100644 index 000000000..99d74e1b8 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/heapq.pyi @@ -0,0 +1,12 @@ +""" +Module: 'heapq' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def heappop(*args, **kwargs) -> Incomplete: ... +def heappush(*args, **kwargs) -> Incomplete: ... +def heapify(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/io.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/io.pyi new file mode 100644 index 000000000..0e8004a7a --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/io.pyi @@ -0,0 +1,37 @@ +""" +Module: 'io' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def open(*args, **kwargs) -> Incomplete: ... + +class IOBase: + def __init__(self, *argv, **kwargs) -> None: ... + +class StringIO: + def write(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def getvalue(self, *args, **kwargs) -> Incomplete: ... + def seek(self, *args, **kwargs) -> Incomplete: ... + def tell(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class BytesIO: + def write(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def getvalue(self, *args, **kwargs) -> Incomplete: ... + def seek(self, *args, **kwargs) -> Incomplete: ... + def tell(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/json.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/json.pyi new file mode 100644 index 000000000..bac3828d4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/json.pyi @@ -0,0 +1,13 @@ +""" +Module: 'json' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def loads(*args, **kwargs) -> Incomplete: ... +def load(*args, **kwargs) -> Incomplete: ... +def dumps(*args, **kwargs) -> Incomplete: ... +def dump(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/lwip.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/lwip.pyi new file mode 100644 index 000000000..74afeef79 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/lwip.pyi @@ -0,0 +1,51 @@ +""" +Module: 'lwip' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +SOCK_RAW: Final[int] = 3 +SOCK_STREAM: Final[int] = 1 +SOCK_DGRAM: Final[int] = 2 +MSG_PEEK: Final[int] = 1 +SO_REUSEADDR: Final[int] = 4 +SOL_SOCKET: Final[int] = 1 +SO_BROADCAST: Final[int] = 32 +TCP_NODELAY: Final[int] = 64 +AF_INET6: Final[int] = 10 +IPPROTO_IP: Final[int] = 0 +AF_INET: Final[int] = 2 +MSG_DONTWAIT: Final[int] = 2 +IP_DROP_MEMBERSHIP: Final[int] = 1025 +IPPROTO_TCP: Final[int] = 6 +IP_ADD_MEMBERSHIP: Final[int] = 1024 + +def reset(*args, **kwargs) -> Incomplete: ... +def print_pcbs(*args, **kwargs) -> Incomplete: ... +def getaddrinfo(*args, **kwargs) -> Incomplete: ... +def callback(*args, **kwargs) -> Incomplete: ... + +class socket: + def recvfrom(self, *args, **kwargs) -> Incomplete: ... + def recv(self, *args, **kwargs) -> Incomplete: ... + def makefile(self, *args, **kwargs) -> Incomplete: ... + def listen(self, *args, **kwargs) -> Incomplete: ... + def settimeout(self, *args, **kwargs) -> Incomplete: ... + def sendall(self, *args, **kwargs) -> Incomplete: ... + def setsockopt(self, *args, **kwargs) -> Incomplete: ... + def setblocking(self, *args, **kwargs) -> Incomplete: ... + def sendto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def connect(self, *args, **kwargs) -> Incomplete: ... + def send(self, *args, **kwargs) -> Incomplete: ... + def bind(self, *args, **kwargs) -> Incomplete: ... + def accept(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/machine.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/machine.pyi new file mode 100644 index 000000000..d942c1988 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/machine.pyi @@ -0,0 +1,416 @@ +""" +Module: 'machine' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +SOFT_RESET: Final[int] = 5 +PWRON_RESET: Final[int] = 1 +WDT_RESET: Final[int] = 3 + +def unique_id(*args, **kwargs) -> Incomplete: ... +def disable_irq(*args, **kwargs) -> Incomplete: ... +def dht_readinto(*args, **kwargs) -> Incomplete: ... +def bitstream(*args, **kwargs) -> Incomplete: ... +def bootloader(*args, **kwargs) -> Incomplete: ... +def deepsleep(*args, **kwargs) -> Incomplete: ... +def enable_irq(*args, **kwargs) -> Incomplete: ... +def reset_cause(*args, **kwargs) -> Incomplete: ... +def soft_reset(*args, **kwargs) -> Incomplete: ... +def time_pulse_us(*args, **kwargs) -> Incomplete: ... +def reset(*args, **kwargs) -> Incomplete: ... +def freq(*args, **kwargs) -> Incomplete: ... +def idle(*args, **kwargs) -> Incomplete: ... +def lightsleep(*args, **kwargs) -> Incomplete: ... + +mem8: Incomplete ## = <8-bit memory> +mem32: Incomplete ## = <32-bit memory> +mem16: Incomplete ## = <16-bit memory> + +class LED: + def on(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class PWM: + def duty_u16(self, *args, **kwargs) -> Incomplete: ... + def freq(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def duty_ns(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2S: + RX: Final[int] = 0 + MONO: Final[int] = 0 + STEREO: Final[int] = 1 + TX: Final[int] = 1 + def shift(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class ADC: + def read_uv(self, *args, **kwargs) -> Incomplete: ... + def read_u16(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2C: + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2CTarget: + IRQ_END_READ: Final[int] = 16 + IRQ_ADDR_MATCH_WRITE: Final[int] = 2 + IRQ_END_WRITE: Final[int] = 32 + IRQ_READ_REQ: Final[int] = 4 + IRQ_ADDR_MATCH_READ: Final[int] = 1 + IRQ_WRITE_REQ: Final[int] = 8 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class UART: + INV_TX: Final[int] = 1 + INV_RX: Final[int] = 2 + CTS: Final[int] = 2 + IRQ_RXIDLE: Final[int] = 1 + IRQ_TXIDLE: Final[int] = 2 + RTS: Final[int] = 1 + def irq(self, *args, **kwargs) -> Incomplete: ... + def sendbreak(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def txdone(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def any(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SoftI2C: + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SoftSPI: + LSB: Final[int] = 1 + MSB: Final[int] = 0 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Timer: + PERIODIC: Final[int] = 2 + ONE_SHOT: Final[int] = 1 + def init(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class WDT: + def timeout_ms(self, *args, **kwargs) -> Incomplete: ... + def feed(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Pin: + OPEN_DRAIN: Final[int] = 2 + IRQ_RISING: Final[int] = 1 + IRQ_FALLING: Final[int] = 2 + IN: Final[int] = 0 + PULL_UP_22K: Final[int] = 3 + OUT: Final[int] = 1 + PULL_UP: Final[int] = 2 + PULL_HOLD: Final[int] = 5 + PULL_DOWN: Final[int] = 0 + DRIVE_2: Final[int] = 3 + DRIVE_1: Final[int] = 2 + DRIVE_0: Final[int] = 1 + PULL_UP_47K: Final[int] = 1 + DRIVE_OFF: Final[int] = 0 + DRIVE_3: Final[int] = 4 + DRIVE_6: Final[int] = 7 + DRIVE_5: Final[int] = 6 + DRIVE_4: Final[int] = 5 + def low(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def on(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def value(self, *args, **kwargs) -> Incomplete: ... + def high(self, *args, **kwargs) -> Incomplete: ... + + class cpu: + GPIO_EMC_16: Pin ## = Pin(GPIO_EMC_16) + GPIO_EMC_15: Pin ## = Pin(GPIO_EMC_15) + GPIO_EMC_17: Pin ## = Pin(GPIO_EMC_17) + GPIO_EMC_18: Pin ## = Pin(GPIO_EMC_18) + GPIO_EMC_12: Pin ## = Pin(GPIO_EMC_12) + GPIO_EMC_14: Pin ## = Pin(GPIO_EMC_14) + GPIO_EMC_13: Pin ## = Pin(GPIO_EMC_13) + WAKEUP: Pin ## = Pin(WAKEUP) + GPIO_EMC_24: Pin ## = Pin(GPIO_EMC_24) + GPIO_EMC_23: Pin ## = Pin(GPIO_EMC_23) + GPIO_EMC_25: Pin ## = Pin(GPIO_EMC_25) + GPIO_EMC_19: Pin ## = Pin(GPIO_EMC_19) + GPIO_EMC_20: Pin ## = Pin(GPIO_EMC_20) + GPIO_EMC_22: Pin ## = Pin(GPIO_EMC_22) + GPIO_EMC_21: Pin ## = Pin(GPIO_EMC_21) + GPIO_EMC_01: Pin ## = Pin(GPIO_EMC_01) + GPIO_EMC_00: Pin ## = Pin(GPIO_EMC_00) + GPIO_EMC_02: Pin ## = Pin(GPIO_EMC_02) + GPIO_EMC_03: Pin ## = Pin(GPIO_EMC_03) + GPIO_B1_13: Pin ## = Pin(GPIO_B1_13) + GPIO_B1_15: Pin ## = Pin(GPIO_B1_15) + GPIO_B1_14: Pin ## = Pin(GPIO_B1_14) + GPIO_EMC_11: Pin ## = Pin(GPIO_EMC_11) + GPIO_EMC_09: Pin ## = Pin(GPIO_EMC_09) + GPIO_EMC_08: Pin ## = Pin(GPIO_EMC_08) + GPIO_EMC_10: Pin ## = Pin(GPIO_EMC_10) + GPIO_EMC_04: Pin ## = Pin(GPIO_EMC_04) + GPIO_EMC_05: Pin ## = Pin(GPIO_EMC_05) + GPIO_EMC_07: Pin ## = Pin(GPIO_EMC_07) + GPIO_EMC_06: Pin ## = Pin(GPIO_EMC_06) + GPIO_SD_B1_04: Pin ## = Pin(GPIO_SD_B1_04) + GPIO_SD_B1_03: Pin ## = Pin(GPIO_SD_B1_03) + GPIO_SD_B1_05: Pin ## = Pin(GPIO_SD_B1_05) + GPIO_SD_B1_06: Pin ## = Pin(GPIO_SD_B1_06) + GPIO_SD_B1_00: Pin ## = Pin(GPIO_SD_B1_00) + GPIO_SD_B1_02: Pin ## = Pin(GPIO_SD_B1_02) + GPIO_SD_B1_01: Pin ## = Pin(GPIO_SD_B1_01) + GPIO_EMC_26: Pin ## = Pin(GPIO_EMC_26) + PMIC_ON_REQ: Pin ## = Pin(PMIC_ON_REQ) + GPIO_SD_B1_11: Pin ## = Pin(GPIO_SD_B1_11) + PMIC_STBY_REQ: Pin ## = Pin(PMIC_STBY_REQ) + GPIO_SD_B1_07: Pin ## = Pin(GPIO_SD_B1_07) + GPIO_SD_B1_08: Pin ## = Pin(GPIO_SD_B1_08) + GPIO_SD_B1_10: Pin ## = Pin(GPIO_SD_B1_10) + GPIO_SD_B1_09: Pin ## = Pin(GPIO_SD_B1_09) + GPIO_EMC_31: Pin ## = Pin(GPIO_EMC_31) + GPIO_EMC_30: Pin ## = Pin(GPIO_EMC_30) + GPIO_EMC_32: Pin ## = Pin(GPIO_EMC_32) + GPIO_EMC_33: Pin ## = Pin(GPIO_EMC_33) + GPIO_EMC_27: Pin ## = Pin(GPIO_EMC_27) + GPIO_EMC_29: Pin ## = Pin(GPIO_EMC_29) + GPIO_EMC_28: Pin ## = Pin(GPIO_EMC_28) + GPIO_EMC_41: Pin ## = Pin(GPIO_EMC_41) + GPIO_EMC_39: Pin ## = Pin(GPIO_EMC_39) + GPIO_EMC_38: Pin ## = Pin(GPIO_EMC_38) + GPIO_EMC_40: Pin ## = Pin(GPIO_EMC_40) + GPIO_EMC_34: Pin ## = Pin(GPIO_EMC_34) + GPIO_EMC_35: Pin ## = Pin(GPIO_EMC_35) + GPIO_EMC_37: Pin ## = Pin(GPIO_EMC_37) + GPIO_EMC_36: Pin ## = Pin(GPIO_EMC_36) + GPIO_AD_B1_03: Pin ## = Pin(GPIO_AD_B1_03) + GPIO_AD_B1_02: Pin ## = Pin(GPIO_AD_B1_02) + GPIO_AD_B1_04: Pin ## = Pin(GPIO_AD_B1_04) + GPIO_AD_B1_05: Pin ## = Pin(GPIO_AD_B1_05) + GPIO_AD_B0_15: Pin ## = Pin(GPIO_AD_B0_15) + GPIO_AD_B1_01: Pin ## = Pin(GPIO_AD_B1_01) + GPIO_AD_B1_00: Pin ## = Pin(GPIO_AD_B1_00) + GPIO_B1_11: Pin ## = Pin(GPIO_B1_11) + GPIO_AD_B1_11: Pin ## = Pin(GPIO_AD_B1_11) + GPIO_AD_B1_10: Pin ## = Pin(GPIO_AD_B1_10) + GPIO_AD_B1_12: Pin ## = Pin(GPIO_AD_B1_12) + GPIO_AD_B1_06: Pin ## = Pin(GPIO_AD_B1_06) + GPIO_AD_B1_07: Pin ## = Pin(GPIO_AD_B1_07) + GPIO_AD_B1_09: Pin ## = Pin(GPIO_AD_B1_09) + GPIO_AD_B1_08: Pin ## = Pin(GPIO_AD_B1_08) + GPIO_AD_B0_04: Pin ## = Pin(GPIO_AD_B0_04) + GPIO_AD_B0_03: Pin ## = Pin(GPIO_AD_B0_03) + GPIO_AD_B0_05: Pin ## = Pin(GPIO_AD_B0_05) + GPIO_AD_B0_06: Pin ## = Pin(GPIO_AD_B0_06) + GPIO_AD_B0_00: Pin ## = Pin(GPIO_AD_B0_00) + GPIO_AD_B0_02: Pin ## = Pin(GPIO_AD_B0_02) + GPIO_AD_B0_01: Pin ## = Pin(GPIO_AD_B0_01) + GPIO_AD_B0_14: Pin ## = Pin(GPIO_AD_B0_14) + GPIO_AD_B0_12: Pin ## = Pin(GPIO_AD_B0_12) + GPIO_AD_B0_11: Pin ## = Pin(GPIO_AD_B0_11) + GPIO_AD_B0_13: Pin ## = Pin(GPIO_AD_B0_13) + GPIO_AD_B0_07: Pin ## = Pin(GPIO_AD_B0_07) + GPIO_AD_B0_08: Pin ## = Pin(GPIO_AD_B0_08) + GPIO_AD_B0_10: Pin ## = Pin(GPIO_AD_B0_10) + GPIO_AD_B0_09: Pin ## = Pin(GPIO_AD_B0_09) + GPIO_B1_01: Pin ## = Pin(GPIO_B1_01) + GPIO_B1_00: Pin ## = Pin(GPIO_B1_00) + GPIO_B1_02: Pin ## = Pin(GPIO_B1_02) + GPIO_B1_03: Pin ## = Pin(GPIO_B1_03) + GPIO_B0_13: Pin ## = Pin(GPIO_B0_13) + GPIO_B0_15: Pin ## = Pin(GPIO_B0_15) + GPIO_B0_14: Pin ## = Pin(GPIO_B0_14) + GPIO_AD_B1_13: Pin ## = Pin(GPIO_AD_B1_13) + GPIO_B1_09: Pin ## = Pin(GPIO_B1_09) + GPIO_B1_08: Pin ## = Pin(GPIO_B1_08) + GPIO_B1_10: Pin ## = Pin(GPIO_B1_10) + GPIO_B1_04: Pin ## = Pin(GPIO_B1_04) + GPIO_B1_05: Pin ## = Pin(GPIO_B1_05) + GPIO_B1_07: Pin ## = Pin(GPIO_B1_07) + GPIO_B1_06: Pin ## = Pin(GPIO_B1_06) + GPIO_B0_02: Pin ## = Pin(GPIO_B0_02) + GPIO_B0_01: Pin ## = Pin(GPIO_B0_01) + GPIO_B0_03: Pin ## = Pin(GPIO_B0_03) + GPIO_B0_04: Pin ## = Pin(GPIO_B0_04) + GPIO_AD_B1_14: Pin ## = Pin(GPIO_AD_B1_14) + GPIO_B0_00: Pin ## = Pin(GPIO_B0_00) + GPIO_AD_B1_15: Pin ## = Pin(GPIO_AD_B1_15) + GPIO_B0_12: Pin ## = Pin(GPIO_B0_12) + GPIO_B0_10: Pin ## = Pin(GPIO_B0_10) + GPIO_B0_09: Pin ## = Pin(GPIO_B0_09) + GPIO_B0_11: Pin ## = Pin(GPIO_B0_11) + GPIO_B0_05: Pin ## = Pin(GPIO_B0_05) + GPIO_B0_06: Pin ## = Pin(GPIO_B0_06) + GPIO_B0_08: Pin ## = Pin(GPIO_B0_08) + GPIO_B0_07: Pin ## = Pin(GPIO_B0_07) + def __init__(self, *argv, **kwargs) -> None: ... + + class board: + J5_22: Pin ## = Pin(GPIO_B0_15) + J5_25: Pin ## = Pin(GPIO_B1_02) + J5_24: Pin ## = Pin(GPIO_B1_01) + J5_23: Pin ## = Pin(GPIO_B1_00) + J5_26: Pin ## = Pin(GPIO_B1_03) + J5_30: Pin ## = Pin(GPIO_B0_03) + J5_29: Pin ## = Pin(GPIO_B0_02) + J5_28: Pin ## = Pin(GPIO_B0_01) + J5_06: Pin ## = Pin(GPIO_B0_06) + J5_17: Pin ## = Pin(GPIO_B0_14) + J5_12: Pin ## = Pin(GPIO_B0_09) + J5_08: Pin ## = Pin(GPIO_B0_08) + J5_07: Pin ## = Pin(GPIO_B0_07) + J5_13: Pin ## = Pin(GPIO_B0_10) + J5_16: Pin ## = Pin(GPIO_B0_13) + J5_15: Pin ## = Pin(GPIO_B0_12) + J5_14: Pin ## = Pin(GPIO_B0_11) + LED_GREEN: Pin ## = Pin(GPIO_AD_B0_10) + SCK_RX: Pin ## = Pin(GPIO_AD_B1_11) + MCK: Pin ## = Pin(GPIO_AD_B1_09) + LED_RED: Pin ## = Pin(GPIO_AD_B0_09) + SCK_TX: Pin ## = Pin(GPIO_AD_B1_14) + WS_RX: Pin ## = Pin(GPIO_AD_B1_10) + SD_TX: Pin ## = Pin(GPIO_AD_B1_13) + SD_RX: Pin ## = Pin(GPIO_AD_B1_12) + J5_32: Pin ## = Pin(GPIO_B0_00) + LED_BLUE: Pin ## = Pin(GPIO_AD_B0_11) + J5_36: Pin ## = Pin(GPIO_AD_B1_13) + J5_35: Pin ## = Pin(GPIO_AD_B1_14) + J5_34: Pin ## = Pin(GPIO_AD_B1_15) + J5_37: Pin ## = Pin(GPIO_AD_B1_12) + J5_50: Pin ## = Pin(GPIO_AD_B0_02) + J5_43: Pin ## = Pin(GPIO_AD_B1_01) + J5_42: Pin ## = Pin(GPIO_AD_B1_00) + WS_TX: Pin ## = Pin(GPIO_AD_B1_15) + J3_12: Pin ## = Pin(GPIO_B1_09) + J3_15: Pin ## = Pin(GPIO_AD_B0_15) + J3_14: Pin ## = Pin(GPIO_AD_B0_14) + J3_13: Pin ## = Pin(GPIO_B1_10) + J3_16: Pin ## = Pin(GPIO_AD_B1_00) + J3_20: Pin ## = Pin(GPIO_AD_B0_12) + J3_19: Pin ## = Pin(GPIO_AD_B0_13) + J3_17: Pin ## = Pin(GPIO_AD_B1_01) + J5_05: Pin ## = Pin(GPIO_B0_05) + J3_11: Pin ## = Pin(GPIO_B1_07) + J3_06: Pin ## = Pin(GPIO_EMC_41) + J3_05: Pin ## = Pin(GPIO_B1_06) + J3_04: Pin ## = Pin(GPIO_B1_11) + J3_07: Pin ## = Pin(GPIO_EMC_40) + J3_10: Pin ## = Pin(GPIO_B1_08) + J3_09: Pin ## = Pin(GPIO_B1_04) + J3_08: Pin ## = Pin(GPIO_B1_05) + J4_13: Pin ## = Pin(GPIO_AD_B1_13) + J4_16: Pin ## = Pin(GPIO_AD_B1_02) + J4_15: Pin ## = Pin(GPIO_AD_B1_15) + J4_14: Pin ## = Pin(GPIO_AD_B1_14) + J4_17: Pin ## = Pin(GPIO_AD_B1_03) + J5_04: Pin ## = Pin(GPIO_B0_04) + J4_20: Pin ## = Pin(GPIO_AD_B0_06) + J4_19: Pin ## = Pin(GPIO_AD_B0_07) + J4_04: Pin ## = Pin(GPIO_AD_B1_04) + J4_12: Pin ## = Pin(GPIO_AD_B1_12) + J4_07: Pin ## = Pin(GPIO_AD_B1_07) + J4_06: Pin ## = Pin(GPIO_AD_B1_06) + J4_05: Pin ## = Pin(GPIO_AD_B1_05) + J4_08: Pin ## = Pin(GPIO_AD_B1_08) + J4_11: Pin ## = Pin(GPIO_AD_B1_11) + J4_10: Pin ## = Pin(GPIO_AD_B1_10) + J4_09: Pin ## = Pin(GPIO_AD_B1_09) + def __init__(self, *argv, **kwargs) -> None: ... + + def __init__(self, *argv, **kwargs) -> None: ... + +class Signal: + def off(self, *args, **kwargs) -> Incomplete: ... + def on(self, *args, **kwargs) -> Incomplete: ... + def value(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class RTC: + ALARM0: Final[int] = 0 + def irq(self, *args, **kwargs) -> Incomplete: ... + def cancel(self, *args, **kwargs) -> Incomplete: ... + def datetime(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def calibration(self, *args, **kwargs) -> Incomplete: ... + def alarm(self, *args, **kwargs) -> Incomplete: ... + def alarm_cancel(self, *args, **kwargs) -> Incomplete: ... + def alarm_left(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SDCard: + def present(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def readblocks(self, *args, **kwargs) -> Incomplete: ... + def writeblocks(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def info(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SPI: + LSB: Final[int] = 1 + MSB: Final[int] = 0 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/math.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/math.pyi new file mode 100644 index 000000000..bbf34db75 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/math.pyi @@ -0,0 +1,55 @@ +""" +Module: 'math' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +inf: float = inf +nan: float = nan +pi: float = 3.141592653589793 +e: float = 2.718281828459045 +tau: float = 6.283185307179586 + +def ldexp(*args, **kwargs) -> Incomplete: ... +def lgamma(*args, **kwargs) -> Incomplete: ... +def trunc(*args, **kwargs) -> Incomplete: ... +def isclose(*args, **kwargs) -> Incomplete: ... +def gamma(*args, **kwargs) -> Incomplete: ... +def isnan(*args, **kwargs) -> Incomplete: ... +def isfinite(*args, **kwargs) -> Incomplete: ... +def isinf(*args, **kwargs) -> Incomplete: ... +def sqrt(*args, **kwargs) -> Incomplete: ... +def sinh(*args, **kwargs) -> Incomplete: ... +def log(*args, **kwargs) -> Incomplete: ... +def tan(*args, **kwargs) -> Incomplete: ... +def tanh(*args, **kwargs) -> Incomplete: ... +def log2(*args, **kwargs) -> Incomplete: ... +def log10(*args, **kwargs) -> Incomplete: ... +def sin(*args, **kwargs) -> Incomplete: ... +def modf(*args, **kwargs) -> Incomplete: ... +def radians(*args, **kwargs) -> Incomplete: ... +def atanh(*args, **kwargs) -> Incomplete: ... +def atan2(*args, **kwargs) -> Incomplete: ... +def atan(*args, **kwargs) -> Incomplete: ... +def ceil(*args, **kwargs) -> Incomplete: ... +def copysign(*args, **kwargs) -> Incomplete: ... +def frexp(*args, **kwargs) -> Incomplete: ... +def acos(*args, **kwargs) -> Incomplete: ... +def pow(*args, **kwargs) -> Incomplete: ... +def asinh(*args, **kwargs) -> Incomplete: ... +def acosh(*args, **kwargs) -> Incomplete: ... +def asin(*args, **kwargs) -> Incomplete: ... +def factorial(*args, **kwargs) -> Incomplete: ... +def fabs(*args, **kwargs) -> Incomplete: ... +def expm1(*args, **kwargs) -> Incomplete: ... +def floor(*args, **kwargs) -> Incomplete: ... +def fmod(*args, **kwargs) -> Incomplete: ... +def cos(*args, **kwargs) -> Incomplete: ... +def degrees(*args, **kwargs) -> Incomplete: ... +def cosh(*args, **kwargs) -> Incomplete: ... +def exp(*args, **kwargs) -> Incomplete: ... +def erf(*args, **kwargs) -> Incomplete: ... +def erfc(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/micropython.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/micropython.pyi new file mode 100644 index 000000000..58bd255a3 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/micropython.pyi @@ -0,0 +1,28 @@ +""" +Module: 'micropython' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def opt_level(*args, **kwargs) -> Incomplete: ... +def mem_info(*args, **kwargs) -> Incomplete: ... +def kbd_intr(*args, **kwargs) -> Incomplete: ... +def qstr_info(*args, **kwargs) -> Incomplete: ... +def schedule(*args, **kwargs) -> Incomplete: ... +def stack_use(*args, **kwargs) -> Incomplete: ... +def heap_unlock(*args, **kwargs) -> Incomplete: ... +def const(*args, **kwargs) -> Incomplete: ... +def heap_lock(*args, **kwargs) -> Incomplete: ... +def alloc_emergency_exception_buf(*args, **kwargs) -> Incomplete: ... + +class RingIO: + def readinto(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def any(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mimxrt.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mimxrt.pyi new file mode 100644 index 000000000..8ecccefdf --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mimxrt.pyi @@ -0,0 +1,14 @@ +""" +Module: 'mimxrt' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class Flash: + def readblocks(self, *args, **kwargs) -> Incomplete: ... + def writeblocks(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip.pyi new file mode 100644 index 000000000..90df55a2e --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip.pyi @@ -0,0 +1,22 @@ +""" +Module: 'mip' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +allowed_mip_url_prefixes: tuple = () +_CHUNK_SIZE: Final[int] = 128 + +def _ensure_path_exists(*args, **kwargs) -> Incomplete: ... +def _install_json(*args, **kwargs) -> Incomplete: ... +def _install_package(*args, **kwargs) -> Incomplete: ... +def _rewrite_url(*args, **kwargs) -> Incomplete: ... +def install(*args, **kwargs) -> Incomplete: ... +def _download_file(*args, **kwargs) -> Incomplete: ... +def const(*args, **kwargs) -> Incomplete: ... +def _check_exists(*args, **kwargs) -> Incomplete: ... +def _chunk(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip/__init__.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip/__init__.pyi new file mode 100644 index 000000000..466c68177 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip/__init__.pyi @@ -0,0 +1,38 @@ +""" +Module: 'mip.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +allowed_mip_url_prefixes: tuple = () +_CHUNK_SIZE: Final[int] = 128 +def _ensure_path_exists(*args, **kwargs) -> Incomplete: + ... + +def _install_json(*args, **kwargs) -> Incomplete: + ... + +def _install_package(*args, **kwargs) -> Incomplete: + ... + +def _rewrite_url(*args, **kwargs) -> Incomplete: + ... + +def install(*args, **kwargs) -> Incomplete: + ... + +def _download_file(*args, **kwargs) -> Incomplete: + ... + +def const(*args, **kwargs) -> Incomplete: + ... + +def _check_exists(*args, **kwargs) -> Incomplete: + ... + +def _chunk(*args, **kwargs) -> Incomplete: + ... + diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/modules.json b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/modules.json new file mode 100644 index 000000000..82be79336 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/modules.json @@ -0,0 +1,80 @@ +{"firmware": {"variant": "", "build": "", "arch": "armv7emdp", "port": "mimxrt", "board": "SEEED_ARCH_MIX", "board_id": "SEEED_ARCH_MIX", "mpy": "v6.3", "ver": "1.26.1", "family": "micropython", "cpu": "MIMXRT1052DVL5B", "version": "1.26.1"}, +"stubber": {"version": "v1.26.3"}, "stubtype": "firmware", +"modules" :[ +{"module": "_asyncio", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_asyncio.pyi"}, +{"module": "_onewire", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/_onewire.pyi"}, +{"module": "array", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/array.pyi"}, +{"module": "asyncio.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/__init__.pyi"}, +{"module": "asyncio.core", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/core.pyi"}, +{"module": "asyncio.event", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/event.pyi"}, +{"module": "asyncio.funcs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/funcs.pyi"}, +{"module": "asyncio.lock", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/lock.pyi"}, +{"module": "asyncio.stream", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/asyncio/stream.pyi"}, +{"module": "binascii", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/binascii.pyi"}, +{"module": "builtins", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/builtins.pyi"}, +{"module": "cmath", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cmath.pyi"}, +{"module": "collections", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/collections.pyi"}, +{"module": "cryptolib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/cryptolib.pyi"}, +{"module": "deflate", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/deflate.pyi"}, +{"module": "dht", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/dht.pyi"}, +{"module": "ds18x20", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ds18x20.pyi"}, +{"module": "errno", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/errno.pyi"}, +{"module": "framebuf", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/framebuf.pyi"}, +{"module": "gc", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/gc.pyi"}, +{"module": "hashlib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/hashlib.pyi"}, +{"module": "heapq", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/heapq.pyi"}, +{"module": "io", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/io.pyi"}, +{"module": "json", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/json.pyi"}, +{"module": "lwip", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/lwip.pyi"}, +{"module": "machine", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/machine.pyi"}, +{"module": "math", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/math.pyi"}, +{"module": "micropython", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/micropython.pyi"}, +{"module": "mimxrt", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mimxrt.pyi"}, +{"module": "mip", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip.pyi"}, +{"module": "mip.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/mip/__init__.pyi"}, +{"module": "network", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/network.pyi"}, +{"module": "ntptime", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ntptime.pyi"}, +{"module": "onewire", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/onewire.pyi"}, +{"module": "os", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/os.pyi"}, +{"module": "platform", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/platform.pyi"}, +{"module": "random", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/random.pyi"}, +{"module": "requests", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests.pyi"}, +{"module": "requests.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests/__init__.pyi"}, +{"module": "select", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/select.pyi"}, +{"module": "socket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/socket.pyi"}, +{"module": "ssl", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ssl.pyi"}, +{"module": "struct", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/struct.pyi"}, +{"module": "sys", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/sys.pyi"}, +{"module": "time", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/time.pyi"}, +{"module": "tls", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/tls.pyi"}, +{"module": "uarray", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uarray.pyi"}, +{"module": "uasyncio.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/__init__.pyi"}, +{"module": "uasyncio.core", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/core.pyi"}, +{"module": "uasyncio.event", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/event.pyi"}, +{"module": "uasyncio.funcs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/funcs.pyi"}, +{"module": "uasyncio.lock", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/lock.pyi"}, +{"module": "uasyncio.stream", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/stream.pyi"}, +{"module": "ubinascii", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ubinascii.pyi"}, +{"module": "ucollections", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucollections.pyi"}, +{"module": "ucryptolib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucryptolib.pyi"}, +{"module": "uctypes", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uctypes.pyi"}, +{"module": "uerrno", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uerrno.pyi"}, +{"module": "uhashlib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uhashlib.pyi"}, +{"module": "uheapq", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uheapq.pyi"}, +{"module": "uio", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uio.pyi"}, +{"module": "ujson", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ujson.pyi"}, +{"module": "umachine", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/umachine.pyi"}, +{"module": "uos", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uos.pyi"}, +{"module": "uplatform", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uplatform.pyi"}, +{"module": "urandom", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urandom.pyi"}, +{"module": "ure", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ure.pyi"}, +{"module": "urequests", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urequests.pyi"}, +{"module": "uselect", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uselect.pyi"}, +{"module": "usocket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usocket.pyi"}, +{"module": "ustruct", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ustruct.pyi"}, +{"module": "usys", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usys.pyi"}, +{"module": "utime", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/utime.pyi"}, +{"module": "uwebsocket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uwebsocket.pyi"}, +{"module": "vfs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/vfs.pyi"}, +{"module": "websocket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/websocket.pyi"} +]} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/network.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/network.pyi new file mode 100644 index 000000000..980b8080a --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/network.pyi @@ -0,0 +1,47 @@ +""" +Module: 'network' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +STA_IF: Final[int] = 0 +AP_IF: Final[int] = 1 + +def route(*args, **kwargs) -> Incomplete: ... +def hostname(*args, **kwargs) -> Incomplete: ... +def ipconfig(*args, **kwargs) -> Incomplete: ... +def country(*args, **kwargs) -> Incomplete: ... + +class PPP: + SEC_NONE: Final[int] = 0 + SEC_PAP: Final[int] = 1 + SEC_CHAP: Final[int] = 2 + def status(self, *args, **kwargs) -> Incomplete: ... + def ipconfig(self, *args, **kwargs) -> Incomplete: ... + def isconnected(self, *args, **kwargs) -> Incomplete: ... + def poll(self, *args, **kwargs) -> Incomplete: ... + def ifconfig(self, *args, **kwargs) -> Incomplete: ... + def config(self, *args, **kwargs) -> Incomplete: ... + def connect(self, *args, **kwargs) -> Incomplete: ... + def disconnect(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class LAN: + PHY_KSZ8081: Final[int] = 0 + PHY_DP83848: Final[int] = 2 + PHY_LAN8720: Final[int] = 3 + PHY_RTL8211F: Final[int] = 4 + IN: Final[int] = 0 + PHY_DP83825: Final[int] = 1 + OUT: Final[int] = 1 + def ipconfig(self, *args, **kwargs) -> Incomplete: ... + def status(self, *args, **kwargs) -> Incomplete: ... + def isconnected(self, *args, **kwargs) -> Incomplete: ... + def active(self, *args, **kwargs) -> Incomplete: ... + def ifconfig(self, *args, **kwargs) -> Incomplete: ... + def config(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ntptime.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ntptime.pyi new file mode 100644 index 000000000..617a66875 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ntptime.pyi @@ -0,0 +1,15 @@ +""" +Module: 'ntptime' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +timeout: int = 1 +host: str = "pool.ntp.org" + +def time(*args, **kwargs) -> Incomplete: ... +def settime(*args, **kwargs) -> Incomplete: ... +def gmtime(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/onewire.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/onewire.pyi new file mode 100644 index 000000000..4994ced18 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/onewire.pyi @@ -0,0 +1,28 @@ +""" +Module: 'onewire' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SKIP_ROM: Final[int] = 204 + SEARCH_ROM: Final[int] = 240 + MATCH_ROM: Final[int] = 85 + def select_rom(self, *args, **kwargs) -> Incomplete: ... + def writebit(self, *args, **kwargs) -> Incomplete: ... + def writebyte(self, *args, **kwargs) -> Incomplete: ... + def _search_rom(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def crc8(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def reset(self, *args, **kwargs) -> Incomplete: ... + def readbit(self, *args, **kwargs) -> Incomplete: ... + def readbyte(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/os.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/os.pyi new file mode 100644 index 000000000..656ede500 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/os.pyi @@ -0,0 +1,61 @@ +""" +Module: 'os' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +sep: str = "/" + +def rmdir(*args, **kwargs) -> Incomplete: ... +def stat(*args, **kwargs) -> Incomplete: ... +def urandom(*args, **kwargs) -> Incomplete: ... +def rename(*args, **kwargs) -> Incomplete: ... +def mount(*args, **kwargs) -> Incomplete: ... +def uname(*args, **kwargs) -> Incomplete: ... +def unlink(*args, **kwargs) -> Incomplete: ... +def statvfs(*args, **kwargs) -> Incomplete: ... +def umount(*args, **kwargs) -> Incomplete: ... +def sync(*args, **kwargs) -> Incomplete: ... +def mkdir(*args, **kwargs) -> Incomplete: ... +def dupterm(*args, **kwargs) -> Incomplete: ... +def chdir(*args, **kwargs) -> Incomplete: ... +def remove(*args, **kwargs) -> Incomplete: ... +def dupterm_notify(*args, **kwargs) -> Incomplete: ... +def listdir(*args, **kwargs) -> Incomplete: ... +def ilistdir(*args, **kwargs) -> Incomplete: ... +def getcwd(*args, **kwargs) -> Incomplete: ... + +class VfsFat: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class VfsLfs2: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/platform.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/platform.pyi new file mode 100644 index 000000000..82a79fc12 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/platform.pyi @@ -0,0 +1,12 @@ +""" +Module: 'platform' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def platform(*args, **kwargs) -> Incomplete: ... +def python_compiler(*args, **kwargs) -> Incomplete: ... +def libc_ver(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/random.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/random.pyi new file mode 100644 index 000000000..2d1a1e8d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/random.pyi @@ -0,0 +1,16 @@ +""" +Module: 'random' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def randrange(*args, **kwargs) -> Incomplete: ... +def random(*args, **kwargs) -> Incomplete: ... +def seed(*args, **kwargs) -> Incomplete: ... +def uniform(*args, **kwargs) -> Incomplete: ... +def choice(*args, **kwargs) -> Incomplete: ... +def randint(*args, **kwargs) -> Incomplete: ... +def getrandbits(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests.pyi new file mode 100644 index 000000000..bd07fad4e --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests.pyi @@ -0,0 +1,24 @@ +""" +Module: 'requests' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def head(*args, **kwargs) -> Incomplete: ... +def patch(*args, **kwargs) -> Incomplete: ... +def post(*args, **kwargs) -> Incomplete: ... +def put(*args, **kwargs) -> Incomplete: ... +def request(*args, **kwargs) -> Incomplete: ... +def delete(*args, **kwargs) -> Incomplete: ... +def get(*args, **kwargs) -> Incomplete: ... + +class Response: + def json(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + + content: Incomplete ## = + text: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests/__init__.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests/__init__.pyi new file mode 100644 index 000000000..2ea7932fc --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/requests/__init__.pyi @@ -0,0 +1,42 @@ +""" +Module: 'requests.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def head(*args, **kwargs) -> Incomplete: + ... + +def patch(*args, **kwargs) -> Incomplete: + ... + +def post(*args, **kwargs) -> Incomplete: + ... + +def put(*args, **kwargs) -> Incomplete: + ... + +def request(*args, **kwargs) -> Incomplete: + ... + +def delete(*args, **kwargs) -> Incomplete: + ... + +def get(*args, **kwargs) -> Incomplete: + ... + + +class Response(): + def json(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + content: Incomplete ## = + text: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: + ... + diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/select.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/select.pyi new file mode 100644 index 000000000..5a861c015 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/select.pyi @@ -0,0 +1,17 @@ +""" +Module: 'select' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +POLLOUT: Final[int] = 4 +POLLIN: Final[int] = 1 +POLLHUP: Final[int] = 16 +POLLERR: Final[int] = 8 + +def select(*args, **kwargs) -> Incomplete: ... +def poll(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/socket.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/socket.pyi new file mode 100644 index 000000000..ec1d560d7 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/socket.pyi @@ -0,0 +1,51 @@ +""" +Module: 'socket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +SOCK_RAW: Final[int] = 3 +SOCK_STREAM: Final[int] = 1 +SOCK_DGRAM: Final[int] = 2 +MSG_PEEK: Final[int] = 1 +SO_REUSEADDR: Final[int] = 4 +SOL_SOCKET: Final[int] = 1 +SO_BROADCAST: Final[int] = 32 +TCP_NODELAY: Final[int] = 64 +AF_INET6: Final[int] = 10 +IPPROTO_IP: Final[int] = 0 +AF_INET: Final[int] = 2 +MSG_DONTWAIT: Final[int] = 2 +IP_DROP_MEMBERSHIP: Final[int] = 1025 +IPPROTO_TCP: Final[int] = 6 +IP_ADD_MEMBERSHIP: Final[int] = 1024 + +def reset(*args, **kwargs) -> Incomplete: ... +def print_pcbs(*args, **kwargs) -> Incomplete: ... +def getaddrinfo(*args, **kwargs) -> Incomplete: ... +def callback(*args, **kwargs) -> Incomplete: ... + +class socket: + def recvfrom(self, *args, **kwargs) -> Incomplete: ... + def recv(self, *args, **kwargs) -> Incomplete: ... + def makefile(self, *args, **kwargs) -> Incomplete: ... + def listen(self, *args, **kwargs) -> Incomplete: ... + def settimeout(self, *args, **kwargs) -> Incomplete: ... + def sendall(self, *args, **kwargs) -> Incomplete: ... + def setsockopt(self, *args, **kwargs) -> Incomplete: ... + def setblocking(self, *args, **kwargs) -> Incomplete: ... + def sendto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def connect(self, *args, **kwargs) -> Incomplete: ... + def send(self, *args, **kwargs) -> Incomplete: ... + def bind(self, *args, **kwargs) -> Incomplete: ... + def accept(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ssl.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ssl.pyi new file mode 100644 index 000000000..9920ed2f4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ssl.pyi @@ -0,0 +1,28 @@ +""" +Module: 'ssl' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +PROTOCOL_TLS_SERVER: Final[int] = 1 +PROTOCOL_DTLS_CLIENT: Final[int] = 2 +PROTOCOL_DTLS_SERVER: Final[int] = 3 +PROTOCOL_TLS_CLIENT: Final[int] = 0 +MBEDTLS_VERSION: Final[str] = "Mbed TLS 3.6.2" +CERT_NONE: Final[int] = 0 +CERT_OPTIONAL: Final[int] = 1 +CERT_REQUIRED: Final[int] = 2 + +def wrap_socket(*args, **kwargs) -> Incomplete: ... + +class SSLContext: + def load_verify_locations(self, *args, **kwargs) -> Incomplete: ... + def wrap_socket(self, *args, **kwargs) -> Incomplete: ... + def load_cert_chain(self, *args, **kwargs) -> Incomplete: ... + + verify_mode: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/struct.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/struct.pyi new file mode 100644 index 000000000..de4675941 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/struct.pyi @@ -0,0 +1,14 @@ +""" +Module: 'struct' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def pack_into(*args, **kwargs) -> Incomplete: ... +def unpack(*args, **kwargs) -> Incomplete: ... +def unpack_from(*args, **kwargs) -> Incomplete: ... +def pack(*args, **kwargs) -> Incomplete: ... +def calcsize(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/sys.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/sys.pyi new file mode 100644 index 000000000..113c321c0 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/sys.pyi @@ -0,0 +1,27 @@ +""" +Module: 'sys' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +platform: str = "mimxrt" +version_info: tuple = () +path: list = [] +version: str = "3.4.0; MicroPython v1.26.1 on 2025-09-11" +ps1: str = ">>> " +ps2: str = "... " +byteorder: str = "little" +modules: dict = {} +argv: list = [] +implementation: tuple = () +maxsize: int = 2147483647 + +def print_exception(*args, **kwargs) -> Incomplete: ... +def exit(*args, **kwargs) -> Incomplete: ... + +stderr: Incomplete ## = +stdout: Incomplete ## = +stdin: Incomplete ## = diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/time.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/time.pyi new file mode 100644 index 000000000..96871d0da --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/time.pyi @@ -0,0 +1,22 @@ +""" +Module: 'time' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def ticks_diff(*args, **kwargs) -> Incomplete: ... +def ticks_add(*args, **kwargs) -> Incomplete: ... +def ticks_cpu(*args, **kwargs) -> Incomplete: ... +def time(*args, **kwargs) -> Incomplete: ... +def ticks_ms(*args, **kwargs) -> Incomplete: ... +def ticks_us(*args, **kwargs) -> Incomplete: ... +def time_ns(*args, **kwargs) -> Incomplete: ... +def localtime(*args, **kwargs) -> Incomplete: ... +def sleep_us(*args, **kwargs) -> Incomplete: ... +def gmtime(*args, **kwargs) -> Incomplete: ... +def sleep_ms(*args, **kwargs) -> Incomplete: ... +def mktime(*args, **kwargs) -> Incomplete: ... +def sleep(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/tls.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/tls.pyi new file mode 100644 index 000000000..34f93f51e --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/tls.pyi @@ -0,0 +1,26 @@ +""" +Module: 'tls' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +PROTOCOL_TLS_SERVER: Final[int] = 1 +PROTOCOL_DTLS_CLIENT: Final[int] = 2 +PROTOCOL_DTLS_SERVER: Final[int] = 3 +PROTOCOL_TLS_CLIENT: Final[int] = 0 +MBEDTLS_VERSION: Final[str] = "Mbed TLS 3.6.2" +CERT_NONE: Final[int] = 0 +CERT_OPTIONAL: Final[int] = 1 +CERT_REQUIRED: Final[int] = 2 + +class SSLContext: + def load_verify_locations(self, *args, **kwargs) -> Incomplete: ... + def set_ciphers(self, *args, **kwargs) -> Incomplete: ... + def wrap_socket(self, *args, **kwargs) -> Incomplete: ... + def load_cert_chain(self, *args, **kwargs) -> Incomplete: ... + def get_ciphers(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uarray.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uarray.pyi new file mode 100644 index 000000000..fb9e16a67 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uarray.pyi @@ -0,0 +1,14 @@ +""" +Module: 'uarray' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +class array: + def extend(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/__init__.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/__init__.pyi new file mode 100644 index 000000000..6c16e98d3 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/__init__.pyi @@ -0,0 +1,278 @@ +""" +Module: 'uasyncio.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +_attrs: dict = {} +def current_task(*args, **kwargs) -> Incomplete: + ... + +def get_event_loop(*args, **kwargs) -> Incomplete: + ... + +def create_task(*args, **kwargs) -> Incomplete: + ... + +def ticks_diff(*args, **kwargs) -> Incomplete: + ... + +def new_event_loop(*args, **kwargs) -> Incomplete: + ... + +def ticks(*args, **kwargs) -> Incomplete: + ... + +def run_until_complete(*args, **kwargs) -> Incomplete: + ... + +def run(*args, **kwargs) -> Incomplete: + ... + +def wait_for_ms(*args, **kwargs) -> Incomplete: + ... + +def sleep_ms(*args, **kwargs) -> Incomplete: + ... + +def ticks_add(*args, **kwargs) -> Incomplete: + ... + +def sleep(*args, **kwargs) -> Incomplete: + ... + + +class TaskQueue(): + def push(self, *args, **kwargs) -> Incomplete: + ... + + def peek(self, *args, **kwargs) -> Incomplete: + ... + + def remove(self, *args, **kwargs) -> Incomplete: + ... + + def pop(self, *args, **kwargs) -> Incomplete: + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + +def open_connection(*args, **kwargs) -> Generator: ## = + ... + +cur_task: Incomplete ## = None +def gather(*args, **kwargs) -> Generator: ## = + ... + + +class Task(): + def __init__(self, *argv, **kwargs) -> None: + ... + +def wait_for(*args, **kwargs) -> Generator: ## = + ... + + +class CancelledError(Exception): + ... +def start_server(*args, **kwargs) -> Generator: ## = + ... + + +class Lock(): + def locked(self, *args, **kwargs) -> Incomplete: + ... + + def release(self, *args, **kwargs) -> Incomplete: + ... + + def acquire(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class StreamWriter(): + def write(self, *args, **kwargs) -> Incomplete: + ... + + def get_extra_info(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def awritestr(*args, **kwargs) -> Generator: ## = + ... + + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + + def drain(*args, **kwargs) -> Generator: ## = + ... + + def readexactly(*args, **kwargs) -> Generator: ## = + ... + + def readinto(*args, **kwargs) -> Generator: ## = + ... + + def read(*args, **kwargs) -> Generator: ## = + ... + + def awrite(*args, **kwargs) -> Generator: ## = + ... + + def readline(*args, **kwargs) -> Generator: ## = + ... + + def aclose(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class StreamReader(): + def write(self, *args, **kwargs) -> Incomplete: + ... + + def get_extra_info(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def awritestr(*args, **kwargs) -> Generator: ## = + ... + + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + + def drain(*args, **kwargs) -> Generator: ## = + ... + + def readexactly(*args, **kwargs) -> Generator: ## = + ... + + def readinto(*args, **kwargs) -> Generator: ## = + ... + + def read(*args, **kwargs) -> Generator: ## = + ... + + def awrite(*args, **kwargs) -> Generator: ## = + ... + + def readline(*args, **kwargs) -> Generator: ## = + ... + + def aclose(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class SingletonGenerator(): + def __init__(self, *argv, **kwargs) -> None: + ... + + +class Loop(): + def get_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def default_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def set_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def run_forever(self, *args, **kwargs) -> Incomplete: + ... + + def run_until_complete(self, *args, **kwargs) -> Incomplete: + ... + + def stop(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def create_task(self, *args, **kwargs) -> Incomplete: + ... + + def call_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + _exc_handler: Incomplete ## = None + def __init__(self, *argv, **kwargs) -> None: + ... + + +class Event(): + def set(self, *args, **kwargs) -> Incomplete: + ... + + def is_set(self, *args, **kwargs) -> Incomplete: + ... + + def clear(self, *args, **kwargs) -> Incomplete: + ... + + def wait(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class ThreadSafeFlag(): + def set(self, *args, **kwargs) -> Incomplete: + ... + + def ioctl(self, *args, **kwargs) -> Incomplete: + ... + + def clear(self, *args, **kwargs) -> Incomplete: + ... + + def wait(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class IOQueue(): + def queue_read(self, *args, **kwargs) -> Incomplete: + ... + + def wait_io_event(self, *args, **kwargs) -> Incomplete: + ... + + def queue_write(self, *args, **kwargs) -> Incomplete: + ... + + def remove(self, *args, **kwargs) -> Incomplete: + ... + + def _enqueue(self, *args, **kwargs) -> Incomplete: + ... + + def _dequeue(self, *args, **kwargs) -> Incomplete: + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class TimeoutError(Exception): + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/core.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/core.pyi new file mode 100644 index 000000000..46cc5e1bc --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/core.pyi @@ -0,0 +1,73 @@ +""" +Module: 'uasyncio.core' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +_exc_context: dict = {} + +def ticks(*args, **kwargs) -> Incomplete: ... +def create_task(*args, **kwargs) -> Incomplete: ... +def _promote_to_task(*args, **kwargs) -> Incomplete: ... +def ticks_diff(*args, **kwargs) -> Incomplete: ... +def run(*args, **kwargs) -> Incomplete: ... +def run_until_complete(*args, **kwargs) -> Incomplete: ... +def current_task(*args, **kwargs) -> Incomplete: ... +def new_event_loop(*args, **kwargs) -> Incomplete: ... +def get_event_loop(*args, **kwargs) -> Incomplete: ... +def sleep_ms(*args, **kwargs) -> Incomplete: ... +def ticks_add(*args, **kwargs) -> Incomplete: ... +def sleep(*args, **kwargs) -> Incomplete: ... + +cur_task: Incomplete ## = None +_task_queue: Incomplete ## = + +class Loop: + def get_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def default_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def set_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def run_forever(self, *args, **kwargs) -> Incomplete: ... + def run_until_complete(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def create_task(self, *args, **kwargs) -> Incomplete: ... + def call_exception_handler(self, *args, **kwargs) -> Incomplete: ... + + _exc_handler: Incomplete ## = None + def __init__(self, *argv, **kwargs) -> None: ... + +class CancelledError(Exception): ... + +class TaskQueue: + def push(self, *args, **kwargs) -> Incomplete: ... + def peek(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Task: + def __init__(self, *argv, **kwargs) -> None: ... + +class TimeoutError(Exception): ... + +class IOQueue: + def queue_read(self, *args, **kwargs) -> Incomplete: ... + def wait_io_event(self, *args, **kwargs) -> Incomplete: ... + def queue_write(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def _enqueue(self, *args, **kwargs) -> Incomplete: ... + def _dequeue(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SingletonGenerator: + def __init__(self, *argv, **kwargs) -> None: ... + +def _stopper(*args, **kwargs) -> Generator: ## = + ... + +_stop_task: Incomplete ## = None +_io_queue: Incomplete ## = diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/event.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/event.pyi new file mode 100644 index 000000000..f7584fd5b --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/event.pyi @@ -0,0 +1,25 @@ +""" +Module: 'uasyncio.event' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +class ThreadSafeFlag: + def set(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def wait(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Event: + def set(self, *args, **kwargs) -> Incomplete: ... + def is_set(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def wait(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/funcs.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/funcs.pyi new file mode 100644 index 000000000..855f60c68 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/funcs.pyi @@ -0,0 +1,22 @@ +""" +Module: 'uasyncio.funcs' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +def wait_for_ms(*args, **kwargs) -> Incomplete: ... +def gather(*args, **kwargs) -> Generator: ## = + ... +def wait_for(*args, **kwargs) -> Generator: ## = + ... + +class _Remove: + def remove(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +def _run(*args, **kwargs) -> Generator: ## = + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/lock.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/lock.pyi new file mode 100644 index 000000000..2ac18cd5c --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/lock.pyi @@ -0,0 +1,16 @@ +""" +Module: 'uasyncio.lock' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +class Lock: + def locked(self, *args, **kwargs) -> Incomplete: ... + def release(self, *args, **kwargs) -> Incomplete: ... + def acquire(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/stream.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/stream.pyi new file mode 100644 index 000000000..60897068f --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uasyncio/stream.pyi @@ -0,0 +1,96 @@ +""" +Module: 'uasyncio.stream' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +def stream_awrite(*args, **kwargs) -> Generator: ## = + ... +def open_connection(*args, **kwargs) -> Generator: ## = + ... +def start_server(*args, **kwargs) -> Generator: ## = + ... + +class StreamWriter: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Server: + def close(self, *args, **kwargs) -> Incomplete: ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def _serve(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Stream: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class StreamReader: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ubinascii.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ubinascii.pyi new file mode 100644 index 000000000..30637870c --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ubinascii.pyi @@ -0,0 +1,15 @@ +""" +Module: 'ubinascii' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def crc32(*args, **kwargs) -> Incomplete: ... +def hexlify(*args, **kwargs) -> Incomplete: ... +def unhexlify(*args, **kwargs) -> Incomplete: ... +def b2a_base64(*args, **kwargs) -> Incomplete: ... +def a2b_base64(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucollections.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucollections.pyi new file mode 100644 index 000000000..dbcad0644 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucollections.pyi @@ -0,0 +1,34 @@ +""" +Module: 'ucollections' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def namedtuple(*args, **kwargs) -> Incomplete: ... + +class OrderedDict: + def popitem(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def values(self, *args, **kwargs) -> Incomplete: ... + def setdefault(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def keys(self, *args, **kwargs) -> Incomplete: ... + def get(self, *args, **kwargs) -> Incomplete: ... + def items(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromkeys(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class deque: + def pop(self, *args, **kwargs) -> Incomplete: ... + def appendleft(self, *args, **kwargs) -> Incomplete: ... + def popleft(self, *args, **kwargs) -> Incomplete: ... + def extend(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucryptolib.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucryptolib.pyi new file mode 100644 index 000000000..294dcdb97 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ucryptolib.pyi @@ -0,0 +1,14 @@ +""" +Module: 'ucryptolib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +class aes: + def encrypt(self, *args, **kwargs) -> Incomplete: ... + def decrypt(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uctypes.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uctypes.pyi new file mode 100644 index 000000000..972fce1e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uctypes.pyi @@ -0,0 +1,50 @@ +""" +Module: 'uctypes' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +VOID: Final[int] = 0 +NATIVE: Final[int] = 2 +PTR: Final[int] = 536870912 +SHORT: Final[int] = 402653184 +LONGLONG: Final[int] = 939524096 +INT8: Final[int] = 134217728 +LITTLE_ENDIAN: Final[int] = 0 +LONG: Final[int] = 671088640 +UINT: Final[int] = 536870912 +ULONG: Final[int] = 536870912 +ULONGLONG: Final[int] = 805306368 +USHORT: Final[int] = 268435456 +UINT8: Final[int] = 0 +UINT16: Final[int] = 268435456 +UINT32: Final[int] = 536870912 +UINT64: Final[int] = 805306368 +INT64: Final[int] = 939524096 +BFUINT16: Final[int] = -805306368 +BFUINT32: Final[int] = -536870912 +BFUINT8: Final[int] = -1073741824 +BFINT8: Final[int] = -939524096 +ARRAY: Final[int] = -1073741824 +BFINT16: Final[int] = -671088640 +BFINT32: Final[int] = -402653184 +BF_LEN: Final[int] = 22 +INT: Final[int] = 671088640 +INT16: Final[int] = 402653184 +INT32: Final[int] = 671088640 +FLOAT64: Final[int] = -134217728 +BF_POS: Final[int] = 17 +BIG_ENDIAN: Final[int] = 1 +FLOAT32: Final[int] = -268435456 + +def sizeof(*args, **kwargs) -> Incomplete: ... +def bytes_at(*args, **kwargs) -> Incomplete: ... +def bytearray_at(*args, **kwargs) -> Incomplete: ... +def addressof(*args, **kwargs) -> Incomplete: ... + +class struct: + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uerrno.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uerrno.pyi new file mode 100644 index 000000000..dc4e06567 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uerrno.pyi @@ -0,0 +1,33 @@ +""" +Module: 'uerrno' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +ENOBUFS: Final[int] = 105 +ENODEV: Final[int] = 19 +ENOENT: Final[int] = 2 +EISDIR: Final[int] = 21 +EIO: Final[int] = 5 +EINVAL: Final[int] = 22 +EPERM: Final[int] = 1 +ETIMEDOUT: Final[int] = 116 +ENOMEM: Final[int] = 12 +EOPNOTSUPP: Final[int] = 95 +ENOTCONN: Final[int] = 128 +errorcode: dict = {} +EAGAIN: Final[int] = 11 +EALREADY: Final[int] = 120 +EBADF: Final[int] = 9 +EADDRINUSE: Final[int] = 112 +EACCES: Final[int] = 13 +EINPROGRESS: Final[int] = 119 +EEXIST: Final[int] = 17 +EHOSTUNREACH: Final[int] = 118 +ECONNABORTED: Final[int] = 113 +ECONNRESET: Final[int] = 104 +ECONNREFUSED: Final[int] = 111 diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uhashlib.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uhashlib.pyi new file mode 100644 index 000000000..eb62f2287 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uhashlib.pyi @@ -0,0 +1,24 @@ +""" +Module: 'uhashlib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +class sha1: + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class sha256: + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class md5: + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uheapq.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uheapq.pyi new file mode 100644 index 000000000..e2cf8fac9 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uheapq.pyi @@ -0,0 +1,13 @@ +""" +Module: 'uheapq' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def heappop(*args, **kwargs) -> Incomplete: ... +def heappush(*args, **kwargs) -> Incomplete: ... +def heapify(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uio.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uio.pyi new file mode 100644 index 000000000..593a3afb9 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uio.pyi @@ -0,0 +1,38 @@ +""" +Module: 'uio' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def open(*args, **kwargs) -> Incomplete: ... + +class IOBase: + def __init__(self, *argv, **kwargs) -> None: ... + +class StringIO: + def write(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def getvalue(self, *args, **kwargs) -> Incomplete: ... + def seek(self, *args, **kwargs) -> Incomplete: ... + def tell(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class BytesIO: + def write(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def getvalue(self, *args, **kwargs) -> Incomplete: ... + def seek(self, *args, **kwargs) -> Incomplete: ... + def tell(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ujson.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ujson.pyi new file mode 100644 index 000000000..73b78f6c6 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ujson.pyi @@ -0,0 +1,14 @@ +""" +Module: 'ujson' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def loads(*args, **kwargs) -> Incomplete: ... +def load(*args, **kwargs) -> Incomplete: ... +def dumps(*args, **kwargs) -> Incomplete: ... +def dump(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/umachine.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/umachine.pyi new file mode 100644 index 000000000..0ce62b49e --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/umachine.pyi @@ -0,0 +1,416 @@ +""" +Module: 'umachine' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +SOFT_RESET: Final[int] = 5 +PWRON_RESET: Final[int] = 1 +WDT_RESET: Final[int] = 3 + +def unique_id(*args, **kwargs) -> Incomplete: ... +def disable_irq(*args, **kwargs) -> Incomplete: ... +def dht_readinto(*args, **kwargs) -> Incomplete: ... +def bitstream(*args, **kwargs) -> Incomplete: ... +def bootloader(*args, **kwargs) -> Incomplete: ... +def deepsleep(*args, **kwargs) -> Incomplete: ... +def enable_irq(*args, **kwargs) -> Incomplete: ... +def reset_cause(*args, **kwargs) -> Incomplete: ... +def soft_reset(*args, **kwargs) -> Incomplete: ... +def time_pulse_us(*args, **kwargs) -> Incomplete: ... +def reset(*args, **kwargs) -> Incomplete: ... +def freq(*args, **kwargs) -> Incomplete: ... +def idle(*args, **kwargs) -> Incomplete: ... +def lightsleep(*args, **kwargs) -> Incomplete: ... + +mem8: Incomplete ## = <8-bit memory> +mem32: Incomplete ## = <32-bit memory> +mem16: Incomplete ## = <16-bit memory> + +class LED: + def on(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class PWM: + def duty_u16(self, *args, **kwargs) -> Incomplete: ... + def freq(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def duty_ns(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2S: + RX: Final[int] = 0 + MONO: Final[int] = 0 + STEREO: Final[int] = 1 + TX: Final[int] = 1 + def shift(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class ADC: + def read_uv(self, *args, **kwargs) -> Incomplete: ... + def read_u16(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2C: + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2CTarget: + IRQ_END_READ: Final[int] = 16 + IRQ_ADDR_MATCH_WRITE: Final[int] = 2 + IRQ_END_WRITE: Final[int] = 32 + IRQ_READ_REQ: Final[int] = 4 + IRQ_ADDR_MATCH_READ: Final[int] = 1 + IRQ_WRITE_REQ: Final[int] = 8 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class UART: + INV_TX: Final[int] = 1 + INV_RX: Final[int] = 2 + CTS: Final[int] = 2 + IRQ_RXIDLE: Final[int] = 1 + IRQ_TXIDLE: Final[int] = 2 + RTS: Final[int] = 1 + def irq(self, *args, **kwargs) -> Incomplete: ... + def sendbreak(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def txdone(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def any(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SoftI2C: + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SoftSPI: + LSB: Final[int] = 1 + MSB: Final[int] = 0 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Timer: + PERIODIC: Final[int] = 2 + ONE_SHOT: Final[int] = 1 + def init(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class WDT: + def timeout_ms(self, *args, **kwargs) -> Incomplete: ... + def feed(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Pin: + OPEN_DRAIN: Final[int] = 2 + IRQ_RISING: Final[int] = 1 + IRQ_FALLING: Final[int] = 2 + IN: Final[int] = 0 + PULL_UP_22K: Final[int] = 3 + OUT: Final[int] = 1 + PULL_UP: Final[int] = 2 + PULL_HOLD: Final[int] = 5 + PULL_DOWN: Final[int] = 0 + DRIVE_2: Final[int] = 3 + DRIVE_1: Final[int] = 2 + DRIVE_0: Final[int] = 1 + PULL_UP_47K: Final[int] = 1 + DRIVE_OFF: Final[int] = 0 + DRIVE_3: Final[int] = 4 + DRIVE_6: Final[int] = 7 + DRIVE_5: Final[int] = 6 + DRIVE_4: Final[int] = 5 + def low(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def on(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def value(self, *args, **kwargs) -> Incomplete: ... + def high(self, *args, **kwargs) -> Incomplete: ... + + class cpu: + GPIO_EMC_16: Pin ## = Pin(GPIO_EMC_16) + GPIO_EMC_15: Pin ## = Pin(GPIO_EMC_15) + GPIO_EMC_17: Pin ## = Pin(GPIO_EMC_17) + GPIO_EMC_18: Pin ## = Pin(GPIO_EMC_18) + GPIO_EMC_12: Pin ## = Pin(GPIO_EMC_12) + GPIO_EMC_14: Pin ## = Pin(GPIO_EMC_14) + GPIO_EMC_13: Pin ## = Pin(GPIO_EMC_13) + WAKEUP: Pin ## = Pin(WAKEUP) + GPIO_EMC_24: Pin ## = Pin(GPIO_EMC_24) + GPIO_EMC_23: Pin ## = Pin(GPIO_EMC_23) + GPIO_EMC_25: Pin ## = Pin(GPIO_EMC_25) + GPIO_EMC_19: Pin ## = Pin(GPIO_EMC_19) + GPIO_EMC_20: Pin ## = Pin(GPIO_EMC_20) + GPIO_EMC_22: Pin ## = Pin(GPIO_EMC_22) + GPIO_EMC_21: Pin ## = Pin(GPIO_EMC_21) + GPIO_EMC_01: Pin ## = Pin(GPIO_EMC_01) + GPIO_EMC_00: Pin ## = Pin(GPIO_EMC_00) + GPIO_EMC_02: Pin ## = Pin(GPIO_EMC_02) + GPIO_EMC_03: Pin ## = Pin(GPIO_EMC_03) + GPIO_B1_13: Pin ## = Pin(GPIO_B1_13) + GPIO_B1_15: Pin ## = Pin(GPIO_B1_15) + GPIO_B1_14: Pin ## = Pin(GPIO_B1_14) + GPIO_EMC_11: Pin ## = Pin(GPIO_EMC_11) + GPIO_EMC_09: Pin ## = Pin(GPIO_EMC_09) + GPIO_EMC_08: Pin ## = Pin(GPIO_EMC_08) + GPIO_EMC_10: Pin ## = Pin(GPIO_EMC_10) + GPIO_EMC_04: Pin ## = Pin(GPIO_EMC_04) + GPIO_EMC_05: Pin ## = Pin(GPIO_EMC_05) + GPIO_EMC_07: Pin ## = Pin(GPIO_EMC_07) + GPIO_EMC_06: Pin ## = Pin(GPIO_EMC_06) + GPIO_SD_B1_04: Pin ## = Pin(GPIO_SD_B1_04) + GPIO_SD_B1_03: Pin ## = Pin(GPIO_SD_B1_03) + GPIO_SD_B1_05: Pin ## = Pin(GPIO_SD_B1_05) + GPIO_SD_B1_06: Pin ## = Pin(GPIO_SD_B1_06) + GPIO_SD_B1_00: Pin ## = Pin(GPIO_SD_B1_00) + GPIO_SD_B1_02: Pin ## = Pin(GPIO_SD_B1_02) + GPIO_SD_B1_01: Pin ## = Pin(GPIO_SD_B1_01) + GPIO_EMC_26: Pin ## = Pin(GPIO_EMC_26) + PMIC_ON_REQ: Pin ## = Pin(PMIC_ON_REQ) + GPIO_SD_B1_11: Pin ## = Pin(GPIO_SD_B1_11) + PMIC_STBY_REQ: Pin ## = Pin(PMIC_STBY_REQ) + GPIO_SD_B1_07: Pin ## = Pin(GPIO_SD_B1_07) + GPIO_SD_B1_08: Pin ## = Pin(GPIO_SD_B1_08) + GPIO_SD_B1_10: Pin ## = Pin(GPIO_SD_B1_10) + GPIO_SD_B1_09: Pin ## = Pin(GPIO_SD_B1_09) + GPIO_EMC_31: Pin ## = Pin(GPIO_EMC_31) + GPIO_EMC_30: Pin ## = Pin(GPIO_EMC_30) + GPIO_EMC_32: Pin ## = Pin(GPIO_EMC_32) + GPIO_EMC_33: Pin ## = Pin(GPIO_EMC_33) + GPIO_EMC_27: Pin ## = Pin(GPIO_EMC_27) + GPIO_EMC_29: Pin ## = Pin(GPIO_EMC_29) + GPIO_EMC_28: Pin ## = Pin(GPIO_EMC_28) + GPIO_EMC_41: Pin ## = Pin(GPIO_EMC_41) + GPIO_EMC_39: Pin ## = Pin(GPIO_EMC_39) + GPIO_EMC_38: Pin ## = Pin(GPIO_EMC_38) + GPIO_EMC_40: Pin ## = Pin(GPIO_EMC_40) + GPIO_EMC_34: Pin ## = Pin(GPIO_EMC_34) + GPIO_EMC_35: Pin ## = Pin(GPIO_EMC_35) + GPIO_EMC_37: Pin ## = Pin(GPIO_EMC_37) + GPIO_EMC_36: Pin ## = Pin(GPIO_EMC_36) + GPIO_AD_B1_03: Pin ## = Pin(GPIO_AD_B1_03) + GPIO_AD_B1_02: Pin ## = Pin(GPIO_AD_B1_02) + GPIO_AD_B1_04: Pin ## = Pin(GPIO_AD_B1_04) + GPIO_AD_B1_05: Pin ## = Pin(GPIO_AD_B1_05) + GPIO_AD_B0_15: Pin ## = Pin(GPIO_AD_B0_15) + GPIO_AD_B1_01: Pin ## = Pin(GPIO_AD_B1_01) + GPIO_AD_B1_00: Pin ## = Pin(GPIO_AD_B1_00) + GPIO_B1_11: Pin ## = Pin(GPIO_B1_11) + GPIO_AD_B1_11: Pin ## = Pin(GPIO_AD_B1_11) + GPIO_AD_B1_10: Pin ## = Pin(GPIO_AD_B1_10) + GPIO_AD_B1_12: Pin ## = Pin(GPIO_AD_B1_12) + GPIO_AD_B1_06: Pin ## = Pin(GPIO_AD_B1_06) + GPIO_AD_B1_07: Pin ## = Pin(GPIO_AD_B1_07) + GPIO_AD_B1_09: Pin ## = Pin(GPIO_AD_B1_09) + GPIO_AD_B1_08: Pin ## = Pin(GPIO_AD_B1_08) + GPIO_AD_B0_04: Pin ## = Pin(GPIO_AD_B0_04) + GPIO_AD_B0_03: Pin ## = Pin(GPIO_AD_B0_03) + GPIO_AD_B0_05: Pin ## = Pin(GPIO_AD_B0_05) + GPIO_AD_B0_06: Pin ## = Pin(GPIO_AD_B0_06) + GPIO_AD_B0_00: Pin ## = Pin(GPIO_AD_B0_00) + GPIO_AD_B0_02: Pin ## = Pin(GPIO_AD_B0_02) + GPIO_AD_B0_01: Pin ## = Pin(GPIO_AD_B0_01) + GPIO_AD_B0_14: Pin ## = Pin(GPIO_AD_B0_14) + GPIO_AD_B0_12: Pin ## = Pin(GPIO_AD_B0_12) + GPIO_AD_B0_11: Pin ## = Pin(GPIO_AD_B0_11) + GPIO_AD_B0_13: Pin ## = Pin(GPIO_AD_B0_13) + GPIO_AD_B0_07: Pin ## = Pin(GPIO_AD_B0_07) + GPIO_AD_B0_08: Pin ## = Pin(GPIO_AD_B0_08) + GPIO_AD_B0_10: Pin ## = Pin(GPIO_AD_B0_10) + GPIO_AD_B0_09: Pin ## = Pin(GPIO_AD_B0_09) + GPIO_B1_01: Pin ## = Pin(GPIO_B1_01) + GPIO_B1_00: Pin ## = Pin(GPIO_B1_00) + GPIO_B1_02: Pin ## = Pin(GPIO_B1_02) + GPIO_B1_03: Pin ## = Pin(GPIO_B1_03) + GPIO_B0_13: Pin ## = Pin(GPIO_B0_13) + GPIO_B0_15: Pin ## = Pin(GPIO_B0_15) + GPIO_B0_14: Pin ## = Pin(GPIO_B0_14) + GPIO_AD_B1_13: Pin ## = Pin(GPIO_AD_B1_13) + GPIO_B1_09: Pin ## = Pin(GPIO_B1_09) + GPIO_B1_08: Pin ## = Pin(GPIO_B1_08) + GPIO_B1_10: Pin ## = Pin(GPIO_B1_10) + GPIO_B1_04: Pin ## = Pin(GPIO_B1_04) + GPIO_B1_05: Pin ## = Pin(GPIO_B1_05) + GPIO_B1_07: Pin ## = Pin(GPIO_B1_07) + GPIO_B1_06: Pin ## = Pin(GPIO_B1_06) + GPIO_B0_02: Pin ## = Pin(GPIO_B0_02) + GPIO_B0_01: Pin ## = Pin(GPIO_B0_01) + GPIO_B0_03: Pin ## = Pin(GPIO_B0_03) + GPIO_B0_04: Pin ## = Pin(GPIO_B0_04) + GPIO_AD_B1_14: Pin ## = Pin(GPIO_AD_B1_14) + GPIO_B0_00: Pin ## = Pin(GPIO_B0_00) + GPIO_AD_B1_15: Pin ## = Pin(GPIO_AD_B1_15) + GPIO_B0_12: Pin ## = Pin(GPIO_B0_12) + GPIO_B0_10: Pin ## = Pin(GPIO_B0_10) + GPIO_B0_09: Pin ## = Pin(GPIO_B0_09) + GPIO_B0_11: Pin ## = Pin(GPIO_B0_11) + GPIO_B0_05: Pin ## = Pin(GPIO_B0_05) + GPIO_B0_06: Pin ## = Pin(GPIO_B0_06) + GPIO_B0_08: Pin ## = Pin(GPIO_B0_08) + GPIO_B0_07: Pin ## = Pin(GPIO_B0_07) + def __init__(self, *argv, **kwargs) -> None: ... + + class board: + J5_22: Pin ## = Pin(GPIO_B0_15) + J5_25: Pin ## = Pin(GPIO_B1_02) + J5_24: Pin ## = Pin(GPIO_B1_01) + J5_23: Pin ## = Pin(GPIO_B1_00) + J5_26: Pin ## = Pin(GPIO_B1_03) + J5_30: Pin ## = Pin(GPIO_B0_03) + J5_29: Pin ## = Pin(GPIO_B0_02) + J5_28: Pin ## = Pin(GPIO_B0_01) + J5_06: Pin ## = Pin(GPIO_B0_06) + J5_17: Pin ## = Pin(GPIO_B0_14) + J5_12: Pin ## = Pin(GPIO_B0_09) + J5_08: Pin ## = Pin(GPIO_B0_08) + J5_07: Pin ## = Pin(GPIO_B0_07) + J5_13: Pin ## = Pin(GPIO_B0_10) + J5_16: Pin ## = Pin(GPIO_B0_13) + J5_15: Pin ## = Pin(GPIO_B0_12) + J5_14: Pin ## = Pin(GPIO_B0_11) + LED_GREEN: Pin ## = Pin(GPIO_AD_B0_10) + SCK_RX: Pin ## = Pin(GPIO_AD_B1_11) + MCK: Pin ## = Pin(GPIO_AD_B1_09) + LED_RED: Pin ## = Pin(GPIO_AD_B0_09) + SCK_TX: Pin ## = Pin(GPIO_AD_B1_14) + WS_RX: Pin ## = Pin(GPIO_AD_B1_10) + SD_TX: Pin ## = Pin(GPIO_AD_B1_13) + SD_RX: Pin ## = Pin(GPIO_AD_B1_12) + J5_32: Pin ## = Pin(GPIO_B0_00) + LED_BLUE: Pin ## = Pin(GPIO_AD_B0_11) + J5_36: Pin ## = Pin(GPIO_AD_B1_13) + J5_35: Pin ## = Pin(GPIO_AD_B1_14) + J5_34: Pin ## = Pin(GPIO_AD_B1_15) + J5_37: Pin ## = Pin(GPIO_AD_B1_12) + J5_50: Pin ## = Pin(GPIO_AD_B0_02) + J5_43: Pin ## = Pin(GPIO_AD_B1_01) + J5_42: Pin ## = Pin(GPIO_AD_B1_00) + WS_TX: Pin ## = Pin(GPIO_AD_B1_15) + J3_12: Pin ## = Pin(GPIO_B1_09) + J3_15: Pin ## = Pin(GPIO_AD_B0_15) + J3_14: Pin ## = Pin(GPIO_AD_B0_14) + J3_13: Pin ## = Pin(GPIO_B1_10) + J3_16: Pin ## = Pin(GPIO_AD_B1_00) + J3_20: Pin ## = Pin(GPIO_AD_B0_12) + J3_19: Pin ## = Pin(GPIO_AD_B0_13) + J3_17: Pin ## = Pin(GPIO_AD_B1_01) + J5_05: Pin ## = Pin(GPIO_B0_05) + J3_11: Pin ## = Pin(GPIO_B1_07) + J3_06: Pin ## = Pin(GPIO_EMC_41) + J3_05: Pin ## = Pin(GPIO_B1_06) + J3_04: Pin ## = Pin(GPIO_B1_11) + J3_07: Pin ## = Pin(GPIO_EMC_40) + J3_10: Pin ## = Pin(GPIO_B1_08) + J3_09: Pin ## = Pin(GPIO_B1_04) + J3_08: Pin ## = Pin(GPIO_B1_05) + J4_13: Pin ## = Pin(GPIO_AD_B1_13) + J4_16: Pin ## = Pin(GPIO_AD_B1_02) + J4_15: Pin ## = Pin(GPIO_AD_B1_15) + J4_14: Pin ## = Pin(GPIO_AD_B1_14) + J4_17: Pin ## = Pin(GPIO_AD_B1_03) + J5_04: Pin ## = Pin(GPIO_B0_04) + J4_20: Pin ## = Pin(GPIO_AD_B0_06) + J4_19: Pin ## = Pin(GPIO_AD_B0_07) + J4_04: Pin ## = Pin(GPIO_AD_B1_04) + J4_12: Pin ## = Pin(GPIO_AD_B1_12) + J4_07: Pin ## = Pin(GPIO_AD_B1_07) + J4_06: Pin ## = Pin(GPIO_AD_B1_06) + J4_05: Pin ## = Pin(GPIO_AD_B1_05) + J4_08: Pin ## = Pin(GPIO_AD_B1_08) + J4_11: Pin ## = Pin(GPIO_AD_B1_11) + J4_10: Pin ## = Pin(GPIO_AD_B1_10) + J4_09: Pin ## = Pin(GPIO_AD_B1_09) + def __init__(self, *argv, **kwargs) -> None: ... + + def __init__(self, *argv, **kwargs) -> None: ... + +class Signal: + def off(self, *args, **kwargs) -> Incomplete: ... + def on(self, *args, **kwargs) -> Incomplete: ... + def value(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class RTC: + ALARM0: Final[int] = 0 + def irq(self, *args, **kwargs) -> Incomplete: ... + def cancel(self, *args, **kwargs) -> Incomplete: ... + def datetime(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def calibration(self, *args, **kwargs) -> Incomplete: ... + def alarm(self, *args, **kwargs) -> Incomplete: ... + def alarm_cancel(self, *args, **kwargs) -> Incomplete: ... + def alarm_left(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SDCard: + def present(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def readblocks(self, *args, **kwargs) -> Incomplete: ... + def writeblocks(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def info(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SPI: + LSB: Final[int] = 1 + MSB: Final[int] = 0 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uos.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uos.pyi new file mode 100644 index 000000000..61bf85b47 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uos.pyi @@ -0,0 +1,62 @@ +""" +Module: 'uos' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +sep: str = "/" + +def rmdir(*args, **kwargs) -> Incomplete: ... +def stat(*args, **kwargs) -> Incomplete: ... +def urandom(*args, **kwargs) -> Incomplete: ... +def rename(*args, **kwargs) -> Incomplete: ... +def mount(*args, **kwargs) -> Incomplete: ... +def uname(*args, **kwargs) -> Incomplete: ... +def unlink(*args, **kwargs) -> Incomplete: ... +def statvfs(*args, **kwargs) -> Incomplete: ... +def umount(*args, **kwargs) -> Incomplete: ... +def sync(*args, **kwargs) -> Incomplete: ... +def mkdir(*args, **kwargs) -> Incomplete: ... +def dupterm(*args, **kwargs) -> Incomplete: ... +def chdir(*args, **kwargs) -> Incomplete: ... +def remove(*args, **kwargs) -> Incomplete: ... +def dupterm_notify(*args, **kwargs) -> Incomplete: ... +def listdir(*args, **kwargs) -> Incomplete: ... +def ilistdir(*args, **kwargs) -> Incomplete: ... +def getcwd(*args, **kwargs) -> Incomplete: ... + +class VfsFat: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class VfsLfs2: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uplatform.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uplatform.pyi new file mode 100644 index 000000000..e1e483acb --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uplatform.pyi @@ -0,0 +1,13 @@ +""" +Module: 'uplatform' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def platform(*args, **kwargs) -> Incomplete: ... +def python_compiler(*args, **kwargs) -> Incomplete: ... +def libc_ver(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urandom.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urandom.pyi new file mode 100644 index 000000000..a177d80ef --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urandom.pyi @@ -0,0 +1,17 @@ +""" +Module: 'urandom' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def randrange(*args, **kwargs) -> Incomplete: ... +def random(*args, **kwargs) -> Incomplete: ... +def seed(*args, **kwargs) -> Incomplete: ... +def uniform(*args, **kwargs) -> Incomplete: ... +def choice(*args, **kwargs) -> Incomplete: ... +def randint(*args, **kwargs) -> Incomplete: ... +def getrandbits(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ure.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ure.pyi new file mode 100644 index 000000000..dc66df2ed --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ure.pyi @@ -0,0 +1,14 @@ +""" +Module: 'ure' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def sub(*args, **kwargs) -> Incomplete: ... +def search(*args, **kwargs) -> Incomplete: ... +def match(*args, **kwargs) -> Incomplete: ... +def compile(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urequests.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urequests.pyi new file mode 100644 index 000000000..3ef9fce15 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/urequests.pyi @@ -0,0 +1,25 @@ +""" +Module: 'urequests' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def head(*args, **kwargs) -> Incomplete: ... +def patch(*args, **kwargs) -> Incomplete: ... +def post(*args, **kwargs) -> Incomplete: ... +def put(*args, **kwargs) -> Incomplete: ... +def request(*args, **kwargs) -> Incomplete: ... +def delete(*args, **kwargs) -> Incomplete: ... +def get(*args, **kwargs) -> Incomplete: ... + +class Response: + def json(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + + content: Incomplete ## = + text: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uselect.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uselect.pyi new file mode 100644 index 000000000..a98692206 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uselect.pyi @@ -0,0 +1,17 @@ +""" +Module: 'uselect' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +POLLOUT: Final[int] = 4 +POLLIN: Final[int] = 1 +POLLHUP: Final[int] = 16 +POLLERR: Final[int] = 8 + +def select(*args, **kwargs) -> Incomplete: ... +def poll(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usocket.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usocket.pyi new file mode 100644 index 000000000..904a683cb --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usocket.pyi @@ -0,0 +1,51 @@ +""" +Module: 'usocket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +SOCK_RAW: Final[int] = 3 +SOCK_STREAM: Final[int] = 1 +SOCK_DGRAM: Final[int] = 2 +MSG_PEEK: Final[int] = 1 +SO_REUSEADDR: Final[int] = 4 +SOL_SOCKET: Final[int] = 1 +SO_BROADCAST: Final[int] = 32 +TCP_NODELAY: Final[int] = 64 +AF_INET6: Final[int] = 10 +IPPROTO_IP: Final[int] = 0 +AF_INET: Final[int] = 2 +MSG_DONTWAIT: Final[int] = 2 +IP_DROP_MEMBERSHIP: Final[int] = 1025 +IPPROTO_TCP: Final[int] = 6 +IP_ADD_MEMBERSHIP: Final[int] = 1024 + +def reset(*args, **kwargs) -> Incomplete: ... +def print_pcbs(*args, **kwargs) -> Incomplete: ... +def getaddrinfo(*args, **kwargs) -> Incomplete: ... +def callback(*args, **kwargs) -> Incomplete: ... + +class socket: + def recvfrom(self, *args, **kwargs) -> Incomplete: ... + def recv(self, *args, **kwargs) -> Incomplete: ... + def makefile(self, *args, **kwargs) -> Incomplete: ... + def listen(self, *args, **kwargs) -> Incomplete: ... + def settimeout(self, *args, **kwargs) -> Incomplete: ... + def sendall(self, *args, **kwargs) -> Incomplete: ... + def setsockopt(self, *args, **kwargs) -> Incomplete: ... + def setblocking(self, *args, **kwargs) -> Incomplete: ... + def sendto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def connect(self, *args, **kwargs) -> Incomplete: ... + def send(self, *args, **kwargs) -> Incomplete: ... + def bind(self, *args, **kwargs) -> Incomplete: ... + def accept(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ustruct.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ustruct.pyi new file mode 100644 index 000000000..8bd48d66d --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/ustruct.pyi @@ -0,0 +1,15 @@ +""" +Module: 'ustruct' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def pack_into(*args, **kwargs) -> Incomplete: ... +def unpack(*args, **kwargs) -> Incomplete: ... +def unpack_from(*args, **kwargs) -> Incomplete: ... +def pack(*args, **kwargs) -> Incomplete: ... +def calcsize(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usys.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usys.pyi new file mode 100644 index 000000000..4b20d4140 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/usys.pyi @@ -0,0 +1,28 @@ +""" +Module: 'usys' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +platform: str = "mimxrt" +version_info: tuple = () +path: list = [] +version: str = "3.4.0; MicroPython v1.26.1 on 2025-09-11" +ps1: str = ">>> " +ps2: str = "... " +byteorder: str = "little" +modules: dict = {} +argv: list = [] +implementation: tuple = () +maxsize: int = 2147483647 + +def print_exception(*args, **kwargs) -> Incomplete: ... +def exit(*args, **kwargs) -> Incomplete: ... + +stderr: Incomplete ## = +stdout: Incomplete ## = +stdin: Incomplete ## = diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/utime.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/utime.pyi new file mode 100644 index 000000000..c7d7e09ae --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/utime.pyi @@ -0,0 +1,23 @@ +""" +Module: 'utime' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def ticks_diff(*args, **kwargs) -> Incomplete: ... +def ticks_add(*args, **kwargs) -> Incomplete: ... +def ticks_cpu(*args, **kwargs) -> Incomplete: ... +def time(*args, **kwargs) -> Incomplete: ... +def ticks_ms(*args, **kwargs) -> Incomplete: ... +def ticks_us(*args, **kwargs) -> Incomplete: ... +def time_ns(*args, **kwargs) -> Incomplete: ... +def localtime(*args, **kwargs) -> Incomplete: ... +def sleep_us(*args, **kwargs) -> Incomplete: ... +def gmtime(*args, **kwargs) -> Incomplete: ... +def sleep_ms(*args, **kwargs) -> Incomplete: ... +def mktime(*args, **kwargs) -> Incomplete: ... +def sleep(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uwebsocket.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uwebsocket.pyi new file mode 100644 index 000000000..395aa5eef --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/uwebsocket.pyi @@ -0,0 +1,18 @@ +""" +Module: 'uwebsocket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +class websocket: + def readline(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/vfs.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/vfs.pyi new file mode 100644 index 000000000..e37567ca5 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/vfs.pyi @@ -0,0 +1,43 @@ +""" +Module: 'vfs' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def umount(*args, **kwargs) -> Incomplete: ... +def mount(*args, **kwargs) -> Incomplete: ... + +class VfsLfs2: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class VfsFat: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/websocket.pyi b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/websocket.pyi new file mode 100644 index 000000000..62bf8e79b --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX/websocket.pyi @@ -0,0 +1,17 @@ +""" +Module: 'websocket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class websocket: + def readline(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... From defb1d96acd94e08381f7939cf0f41e77d113af7 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 20 Nov 2025 21:16:22 +1100 Subject: [PATCH 2/5] Add MIMXRT1010_EVK (mimxrt) v1.26.1 Signed-off-by: Andrew Leech --- .../LICENSE.md | 22 + .../README.md | 37 + .../__builtins__.pyi | 28 + .../_onewire.pyi | 15 + .../binascii.pyi | 61 + .../cmath.pyi | 84 + .../deflate.pyi | 89 + .../dht.pyi | 26 + .../ds18x20.pyi | 18 + .../errno.pyi | 97 + .../framebuf.pyi | 247 ++ .../gc.pyi | 112 + .../hashlib.pyi | 94 + .../heapq.pyi | 46 + .../machine.pyi | 3052 +++++++++++++++++ .../math.pyi | 269 ++ .../micropython.pyi | 346 ++ .../mimxrt.pyi | 14 + .../network.pyi | 386 +++ .../onewire.pyi | 28 + .../platform.pyi | 51 + .../pyproject.toml | 102 + .../random.pyi | 115 + .../select.pyi | 118 + .../socket.pyi | 419 +++ .../time.pyi | 306 ++ .../uarray.pyi | 2 + .../uasyncio.pyi | 2 + .../ubinascii.pyi | 2 + .../ubluetooth.pyi | 2 + .../ucollections.pyi | 15 + .../ucryptolib.pyi | 2 + .../uctypes.pyi | 164 + .../uerrno.pyi | 2 + .../uhashlib.pyi | 2 + .../uheapq.pyi | 2 + .../uio.pyi | 2 + .../ujson.pyi | 2 + .../umachine.pyi | 2 + .../uos.pyi | 2 + .../uplatform.pyi | 2 + .../urandom.pyi | 2 + .../ure.pyi | 2 + .../usb/device.pyi | 10 + .../usb/device/cdc.pyi | 77 + .../uselect.pyi | 2 + .../usocket.pyi | 2 + .../ussl.pyi | 2 + .../ustruct.pyi | 2 + .../usys.pyi | 2 + .../utime.pyi | 2 + .../uwebsocket.pyi | 2 + .../uzlib.pyi | 2 + .../vfs.pyi | 240 ++ .../_onewire.pyi | 15 + .../binascii.pyi | 61 + .../cmath.pyi | 84 + .../deflate.pyi | 89 + .../dht.pyi | 26 + .../doc_stubs.json | 476 +++ .../ds18x20.pyi | 18 + .../errno.pyi | 97 + .../firmware_stubs.json | 69 + .../framebuf.pyi | 247 ++ .../gc.pyi | 112 + .../hashlib.pyi | 94 + .../heapq.pyi | 46 + .../machine.pyi | 3052 +++++++++++++++++ .../math.pyi | 269 ++ .../micropython.pyi | 346 ++ .../mimxrt.pyi | 14 + .../network.pyi | 386 +++ .../onewire.pyi | 28 + .../platform.pyi | 51 + .../random.pyi | 115 + .../select.pyi | 118 + .../socket.pyi | 419 +++ .../time.pyi | 306 ++ .../uarray.pyi | 2 + .../uasyncio.pyi | 2 + .../ubinascii.pyi | 2 + .../ubluetooth.pyi | 2 + .../ucollections.pyi | 137 + .../ucryptolib.pyi | 2 + .../uctypes.pyi | 164 + .../uerrno.pyi | 2 + .../uhashlib.pyi | 2 + .../uheapq.pyi | 2 + .../uio.pyi | 2 + .../ujson.pyi | 2 + .../umachine.pyi | 2 + .../uos.pyi | 2 + .../uplatform.pyi | 2 + .../urandom.pyi | 2 + .../ure.pyi | 2 + .../usb/device.pyi | 10 + .../usb/device/cdc.pyi | 77 + .../uselect.pyi | 2 + .../usocket.pyi | 2 + .../ussl.pyi | 2 + .../ustruct.pyi | 2 + .../usys.pyi | 2 + .../utime.pyi | 2 + .../uwebsocket.pyi | 2 + .../uzlib.pyi | 2 + .../vfs.pyi | 240 ++ .../_asyncio.pyi | 18 + .../_onewire.pyi | 15 + .../array.pyi | 13 + .../asyncio/__init__.pyi | 278 ++ .../asyncio/core.pyi | 73 + .../asyncio/event.pyi | 25 + .../asyncio/funcs.pyi | 22 + .../asyncio/lock.pyi | 16 + .../asyncio/stream.pyi | 96 + .../binascii.pyi | 14 + .../builtins.pyi | 305 ++ .../cmath.pyi | 21 + .../collections.pyi | 33 + .../deflate.pyi | 22 + .../dht.pyi | 26 + .../ds18x20.pyi | 18 + .../errno.pyi | 33 + .../framebuf.pyi | 35 + .../gc.pyi | 16 + .../hashlib.pyi | 13 + .../heapq.pyi | 12 + .../io.pyi | 37 + .../json.pyi | 13 + .../machine.pyi | 304 ++ .../math.pyi | 55 + .../micropython.pyi | 28 + .../mimxrt.pyi | 14 + .../modules.json | 69 + .../network.pyi | 16 + .../onewire.pyi | 28 + .../os.pyi | 61 + .../platform.pyi | 12 + .../random.pyi | 16 + .../select.pyi | 17 + .../socket.pyi | 44 + .../struct.pyi | 14 + .../sys.pyi | 27 + .../time.pyi | 22 + .../uarray.pyi | 14 + .../uasyncio/__init__.pyi | 278 ++ .../uasyncio/core.pyi | 73 + .../uasyncio/event.pyi | 25 + .../uasyncio/funcs.pyi | 22 + .../uasyncio/lock.pyi | 16 + .../uasyncio/stream.pyi | 96 + .../ubinascii.pyi | 15 + .../ucollections.pyi | 34 + .../uctypes.pyi | 50 + .../uerrno.pyi | 33 + .../uhashlib.pyi | 14 + .../uheapq.pyi | 13 + .../uio.pyi | 38 + .../ujson.pyi | 14 + .../umachine.pyi | 304 ++ .../uos.pyi | 62 + .../uplatform.pyi | 13 + .../urandom.pyi | 17 + .../ure.pyi | 14 + .../usb/device.pyi | 10 + .../usb/device/cdc.pyi | 77 + .../uselect.pyi | 17 + .../usocket.pyi | 44 + .../ustruct.pyi | 15 + .../usys.pyi | 28 + .../utime.pyi | 23 + .../vfs.pyi | 43 + 172 files changed, 17229 insertions(+) create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/LICENSE.md create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/README.md create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/__builtins__.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/_onewire.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/binascii.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/cmath.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/deflate.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/dht.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ds18x20.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/errno.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/framebuf.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/gc.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/hashlib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/heapq.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/machine.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/math.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/micropython.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/mimxrt.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/network.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/onewire.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/platform.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/pyproject.toml create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/random.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/select.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/socket.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/time.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uarray.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uasyncio.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ubinascii.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ubluetooth.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ucollections.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ucryptolib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uctypes.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uerrno.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uhashlib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uheapq.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uio.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ujson.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/umachine.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uos.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uplatform.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/urandom.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ure.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usb/device.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usb/device/cdc.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uselect.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usocket.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ussl.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ustruct.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usys.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/utime.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uwebsocket.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uzlib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/vfs.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/_onewire.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/binascii.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/cmath.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/deflate.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/dht.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/doc_stubs.json create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/errno.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/firmware_stubs.json create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/framebuf.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/gc.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/hashlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/heapq.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/machine.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/math.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/micropython.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/mimxrt.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/network.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/platform.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/random.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/select.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/socket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/time.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uarray.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uasyncio.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ubinascii.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ubluetooth.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ucollections.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ucryptolib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uctypes.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uerrno.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uhashlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uheapq.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uio.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ujson.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/umachine.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uos.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uplatform.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/urandom.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ure.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usb/device.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usb/device/cdc.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uselect.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usocket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ussl.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ustruct.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usys.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/utime.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uwebsocket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uzlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/vfs.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_asyncio.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_onewire.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/array.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/core.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/event.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/funcs.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/lock.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/stream.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/binascii.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/builtins.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/cmath.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/collections.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/deflate.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/dht.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/errno.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/framebuf.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/gc.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/hashlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/heapq.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/io.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/json.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/machine.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/math.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/micropython.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/mimxrt.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/modules.json create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/network.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/os.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/platform.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/random.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/select.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/socket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/struct.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/sys.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/time.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uarray.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/core.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/event.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/funcs.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/lock.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/stream.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ubinascii.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ucollections.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uctypes.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uerrno.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uhashlib.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uheapq.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uio.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ujson.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/umachine.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uos.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uplatform.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/urandom.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ure.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device/cdc.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uselect.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usocket.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ustruct.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usys.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/utime.pyi create mode 100644 stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/vfs.pyi diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/LICENSE.md b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/LICENSE.md new file mode 100644 index 000000000..15d4b4693 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/LICENSE.md @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2022 Jos Verlinde + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/README.md b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/README.md new file mode 100644 index 000000000..72bc1b836 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/README.md @@ -0,0 +1,37 @@ +# micropython-mimxrt-mimxrt1010_evk-stubs + + +This is a stub-only package for MicroPython. +It is intended to be installed in a projects virtual environment to allow static type checkers and intellisense features to be used while writing Micropython code. + +The version of this package is alligned the the version of the MicroPython firmware. + - Major, Minor and Patch levels are alligned to the same version as the firmware. + - The post release level is used to publish new releases of the stubs. + +For `Micropython 1.17` the stubs are published as `1.17.post1` ... `1.17.post2` +for `Micropython 1.18` the stubs are published as `1.18.post1` ... `1.18.post2` + +To install the latest stubs: +`pip install -I micropython--stubs` where port is the port of the MicroPython firmware. + +To install the stubs for an older version, such as MicroPython 1.17: +`pip install micropython-stm32-stubs==1.17.*` which will install the last post release of the stubs for MicroPython 1.17. + + +As the creation of the stubs, and merging of the different types is still going though improvements, the stub packages are marked as Beta. +To upgrade stubs to the latest stubs for a specific version use `pip install micropython-stm32-stubs==1.17.* --upgrade` + +If you have suggestions or find any issues with the stubs, please report them in the [MicroPython-stubs Discussions](https://github.com/Josverl/micropython-stubs/discussions) + +For an overview of Micropython Stubs please see: https://micropython-stubs.readthedocs.io/en/main/ + * List of all stubs : https://micropython-stubs.readthedocs.io/en/main/firmware_grp.html + + + +Included stubs: +* Merged stubs from `stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged` +* Core stubs from `stubs/micropython-core` + + +origin | Family | Port | Board | Version +-------|--------|------|-------|-------- diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/__builtins__.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/__builtins__.pyi new file mode 100644 index 000000000..5d9ece1df --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/__builtins__.pyi @@ -0,0 +1,28 @@ +"""Allows for type checking of Micropython specific builtins by pyright and pylance. +""" + +from typing import Tuple, TypeVar + +Const_T = TypeVar("Const_T", int, float, str, bytes, Tuple) # constant + +def const(expr: Const_T) -> Const_T: + """ + Used to declare that the expression is a constant so that the compiler can + optimise it. The use of this function should be as follows:: + + from micropython import const + + CONST_X = const(123) + CONST_Y = const(2 * CONST_X + 1) + + Constants declared this way are still accessible as global variables from + outside the module they are declared in. On the other hand, if a constant + begins with an underscore then it is hidden, it is not available as a global + variable, and does not take up any memory during execution. + + This `const` function is recognised directly by the MicroPython parser and is + provided as part of the :mod:`micropython` module mainly so that scripts can be + written which run under both CPython and MicroPython, by following the above + pattern. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/_onewire.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/_onewire.pyi new file mode 100644 index 000000000..20bb1a901 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/_onewire.pyi @@ -0,0 +1,15 @@ +""" +Module: '_onewire' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def reset(*args, **kwargs) -> Incomplete: ... +def writebyte(*args, **kwargs) -> Incomplete: ... +def writebit(*args, **kwargs) -> Incomplete: ... +def crc8(*args, **kwargs) -> Incomplete: ... +def readbyte(*args, **kwargs) -> Incomplete: ... +def readbit(*args, **kwargs) -> Incomplete: ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/binascii.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/binascii.pyi new file mode 100644 index 000000000..ce3060423 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/binascii.pyi @@ -0,0 +1,61 @@ +""" +Binary/ASCII conversions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/binascii.html + +CPython module: :mod:`python:binascii` https://docs.python.org/3/library/binascii.html . + +This module implements conversions between binary data and various +encodings of it in ASCII form (in both directions). + +--- +Module: 'binascii' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any, Optional +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def crc32(data, value: Optional[Any] = None) -> Incomplete: + """ + Compute CRC-32, the 32-bit checksum of *data*, starting with an initial CRC + of *value*. The default initial CRC is zero. The algorithm is consistent + with the ZIP file checksum. + """ + ... + +def hexlify(data: bytes, sep: str | bytes = ..., /) -> bytes: + """ + Convert the bytes in the *data* object to a hexadecimal representation. + Returns a bytes object. + + If the additional argument *sep* is supplied it is used as a separator + between hexadecimal values. + """ + ... + +def unhexlify(data: str | bytes, /) -> bytes: + """ + Convert hexadecimal data to binary representation. Returns bytes string. + (i.e. inverse of hexlify) + """ + ... + +def b2a_base64(data: bytes, /) -> bytes: + """ + Encode binary data in base64 format, as in `RFC 3548 + `_. Returns the encoded data + followed by a newline character if newline is true, as a bytes object. + """ + ... + +def a2b_base64(data: str | bytes, /) -> bytes: + """ + Decode base64-encoded data, ignoring invalid characters in the input. + Conforms to `RFC 2045 s.6.8 `_. + Returns a bytes object. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/cmath.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/cmath.pyi new file mode 100644 index 000000000..3dd30414a --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/cmath.pyi @@ -0,0 +1,84 @@ +""" +Mathematical functions for complex numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/cmath.html + +CPython module: :mod:`python:cmath` https://docs.python.org/3/library/cmath.html . + +The ``cmath`` module provides some basic mathematical functions for +working with complex numbers. + +Availability: not available on WiPy and ESP8266. Floating point support +required for this module. + +--- +Module: 'cmath' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsComplex, SupportsFloat, SupportsIndex, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_C: TypeAlias = SupportsFloat | SupportsComplex | SupportsIndex | complex + +e: float = 2.7182818 +"""base of the natural logarithm""" +pi: float = 3.1415928 +"""the ratio of a circle's circumference to its diameter""" + +def polar(z: _C, /) -> Tuple: + """ + Returns, as a tuple, the polar form of ``z``. + """ + ... + +def sqrt(z: _C, /) -> complex: + """ + Return the square-root of ``z``. + """ + ... + +def rect(r: float, phi: float, /) -> float: + """ + Returns the complex number with modulus ``r`` and phase ``phi``. + """ + ... + +def sin(z: _C, /) -> float: + """ + Return the sine of ``z``. + """ + ... + +def exp(z: _C, /) -> float: + """ + Return the exponential of ``z``. + """ + ... + +def cos(z: _C, /) -> float: + """ + Return the cosine of ``z``. + """ + ... + +def phase(z: _C, /) -> float: + """ + Returns the phase of the number ``z``, in the range (-pi, +pi]. + """ + ... + +def log(z: _C, /) -> float: + """ + Return the natural logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... + +def log10(z: _C, /) -> float: + """ + Return the base-10 logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/deflate.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/deflate.pyi new file mode 100644 index 000000000..6255589fe --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/deflate.pyi @@ -0,0 +1,89 @@ +""" +Deflate compression & decompression. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/deflate.html + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ +(commonly used in the zlib library and gzip archiver). + +**Availability:** + +* Added in MicroPython v1.21. + +* Decompression: Enabled via the ``MICROPY_PY_DEFLATE`` build option, on by default + on ports with the "extra features" level or higher (which is most boards). + +* Compression: Enabled via the ``MICROPY_PY_DEFLATE_COMPRESS`` build option, on + by default on ports with the "full features" level or higher (generally this means + you need to build your own firmware to enable this). + +--- +Module: 'deflate' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +GZIP: Final[int] = 3 +"""Supported values for the *format* parameter.""" +RAW: Final[int] = 1 +"""Supported values for the *format* parameter.""" +ZLIB: Final[int] = 2 +"""Supported values for the *format* parameter.""" +AUTO: Final[int] = 0 +"""Supported values for the *format* parameter.""" + +class DeflateIO: + """ + This class can be used to wrap a *stream* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + The *stream* must be a blocking stream. Non-blocking streams are currently + not supported. + + The *format* can be set to any of the constants defined below, and defaults + to ``AUTO`` which for decompressing will auto-detect gzip or zlib streams, + and for compressing it will generate a raw stream. + + The *wbits* parameter sets the base-2 logarithm of the DEFLATE dictionary + window size. So for example, setting *wbits* to ``10`` sets the window size + to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to + window sizes of 32 to 32k bytes). + + If *wbits* is set to ``0`` (the default), then for compression a window size + of 256 bytes will be used (as if *wbits* was set to 8). For decompression, it + depends on the format: + + * ``RAW`` will use 256 bytes (corresponding to *wbits* set to 8). + * ``ZLIB`` (or ``AUTO`` with zlib detected) will use the value from the zlib + header. + * ``GZIP`` (or ``AUTO`` with gzip detected) will use 32 kilobytes + (corresponding to *wbits* set to 15). + + See the :ref:`window size ` notes below for more information + about the window size, zlib, and gzip streams. + + If *close* is set to ``True`` then the underlying stream will be closed + automatically when the :class:`deflate.DeflateIO` stream is closed. This is + useful if you want to return a :class:`deflate.DeflateIO` stream that wraps + another stream and not have the caller need to know about managing the + underlying stream. + + If compression is enabled, a given :class:`deflate.DeflateIO` instance + supports both reading and writing. For example, a bidirectional stream like + a socket can be wrapped, which allows for compression/decompression in both + directions. + """ + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, stream, format=AUTO, wbits=0, close=False, /) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/dht.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/dht.pyi new file mode 100644 index 000000000..f6c87a348 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/dht.pyi @@ -0,0 +1,26 @@ +""" +Module: 'dht' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def dht_readinto(*args, **kwargs) -> Incomplete: ... + +class DHTBase: + def measure(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT22: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT11: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ds18x20.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ds18x20.pyi new file mode 100644 index 000000000..96f095cd9 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ds18x20.pyi @@ -0,0 +1,18 @@ +""" +Module: 'ds18x20' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def const(*args, **kwargs) -> Incomplete: ... + +class DS18X20: + def read_scratch(self, *args, **kwargs) -> Incomplete: ... + def read_temp(self, *args, **kwargs) -> Incomplete: ... + def write_scratch(self, *args, **kwargs) -> Incomplete: ... + def convert_temp(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/errno.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/errno.pyi new file mode 100644 index 000000000..4bd9127a3 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/errno.pyi @@ -0,0 +1,97 @@ +""" +System error codes. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/errno.html + +CPython module: :mod:`python:errno` https://docs.python.org/3/library/errno.html . + +This module provides access to symbolic error codes for `OSError` exception. +A particular inventory of codes depends on :term:`MicroPython port`. + +--- +Module: 'errno' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +ENOBUFS: Final[int] = 105 +"""No buffer space available""" +ENODEV: Final[int] = 19 +"""No such device""" +ENOENT: Final[int] = 2 +"""No such file or directory""" +EISDIR: Final[int] = 21 +"""Is a directory""" +EIO: Final[int] = 5 +"""I/O error""" +EINVAL: Final[int] = 22 +"""Invalid argument""" +EPERM: Final[int] = 1 +"""Operation not permitted""" +ETIMEDOUT: Final[int] = 116 +"""Connection timed out""" +ENOMEM: Final[int] = 12 +"""Out of memory""" +EOPNOTSUPP: Final[int] = 95 +"""Operation not supported""" +ENOTCONN: Final[int] = 128 +"""Transport endpoint is not connected""" +errorcode: dict = {} +"""\ +Dictionary mapping numeric error codes to strings with symbolic error +code (see above):: + +>>> print(errno.errorcode[errno.EEXIST]) +EEXIST +""" +EAGAIN: Final[int] = 11 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EALREADY: Final[int] = 120 +"""Operation already in progress""" +EBADF: Final[int] = 9 +"""Bad file descriptor""" +EADDRINUSE: Final[int] = 112 +"""Address already in use""" +EACCES: Final[int] = 13 +"""Permission denied""" +EINPROGRESS: Final[int] = 119 +"""Operation now in progress""" +EEXIST: Final[int] = 17 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EHOSTUNREACH: Final[int] = 118 +"""Host is unreachable""" +ECONNABORTED: Final[int] = 113 +"""Connection aborted""" +ECONNRESET: Final[int] = 104 +"""Connection reset by peer""" +ECONNREFUSED: Final[int] = 111 +"""Connection refused""" +ENOTSUP: Final[int] = ... +"""Operation not supported""" diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/framebuf.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/framebuf.pyi new file mode 100644 index 000000000..6f252c067 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/framebuf.pyi @@ -0,0 +1,247 @@ +""" +Frame buffer manipulation. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/framebuf.html + +This module provides a general frame buffer which can be used to create +bitmap images, which can then be sent to a display. + +--- +Module: 'framebuf' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Optional, Union, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +MONO_HMSB: Final[int] = 4 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +MONO_HLSB: Final[int] = 3 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +RGB565: Final[int] = 1 +"""Red Green Blue (16-bit, 5+6+5) color format""" +MONO_VLSB: Final[int] = 0 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are vertically mapped with +bit 0 being nearest the top of the screen. Consequently each byte occupies +8 vertical pixels. Subsequent bytes appear at successive horizontal +locations until the rightmost edge is reached. Further bytes are rendered +at locations starting at the leftmost edge, 8 pixels lower. +""" +MVLSB: Final[int] = 0 +GS2_HMSB: Final[int] = 5 +"""Grayscale (2-bit) color format""" +GS8: Final[int] = 6 +"""Grayscale (8-bit) color format""" +GS4_HMSB: Final[int] = 2 +"""Grayscale (4-bit) color format""" + +def FrameBuffer1(*args, **kwargs) -> Incomplete: ... + +class FrameBuffer: + """ + The FrameBuffer class provides a pixel buffer which can be drawn upon with + pixels, lines, rectangles, text and even other FrameBuffer's. It is useful + when generating output for displays. + + For example:: + + import framebuf + + # FrameBuffer needs 2 bytes for every RGB565 pixel + fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565) + + fbuf.fill(0) + fbuf.text('MicroPython!', 0, 0, 0xffff) + fbuf.hline(0, 9, 96, 0xffff) + """ + def poly(self, x, y, coords, c, f: Union[bool, int] = False, /) -> Incomplete: + """ + Given a list of coordinates, draw an arbitrary (convex or concave) closed + polygon at the given x, y location using the given color. + + The *coords* must be specified as a :mod:`array` of integers, e.g. + ``array('h', [x0, y0, x1, y1, ... xn, yn])``. + + The optional *f* parameter can be set to ``True`` to fill the polygon. + Otherwise just a one pixel outline is drawn. + """ + ... + def vline(self, x: int, y: int, h: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + + @overload + def pixel(self, x: int, y: int, /) -> int: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + + @overload + def pixel(self, x: int, y: int, c: int, /) -> None: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + def text(self, s: str, x: int, y: int, c: int = 1, /) -> None: + """ + Write text to the FrameBuffer using the coordinates as the upper-left + corner of the text. The color of the text can be defined by the optional + argument but is otherwise a default value of 1. All characters have + dimensions of 8x8 pixels and there is currently no way to change the font. + """ + ... + def rect(self, x: int, y: int, w: int, h: int, c: int, f: Union[bool, int] = False, /) -> None: + """ + Draw a rectangle at the given location, size and color. + + The optional *f* parameter can be set to ``True`` to fill the rectangle. + Otherwise just a one pixel outline is drawn. + """ + ... + def scroll(self, xstep: int, ystep: int, /) -> None: + """ + Shift the contents of the FrameBuffer by the given vector. This may + leave a footprint of the previous colors in the FrameBuffer. + """ + ... + def ellipse(self, x, y, xr, yr, c, f: Union[bool, int] = False, m: Optional[int] = None) -> None: + """ + Draw an ellipse at the given location. Radii *xr* and *yr* define the + geometry; equal values cause a circle to be drawn. The *c* parameter + defines the color. + + The optional *f* parameter can be set to ``True`` to fill the ellipse. + Otherwise just a one pixel outline is drawn. + + The optional *m* parameter enables drawing to be restricted to certain + quadrants of the ellipse. The LS four bits determine which quadrants are + to be drawn, with bit 0 specifying Q1, b1 Q2, b2 Q3 and b3 Q4. Quadrants + are numbered counterclockwise with Q1 being top right. + """ + ... + def line(self, x1: int, y1: int, x2: int, y2: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def blit( + self, + fbuf: FrameBuffer, + x: int, + y: int, + key: int = -1, + palette: Optional[bytes] = None, + /, + ) -> None: + """ + Draw another FrameBuffer on top of the current one at the given coordinates. + If *key* is specified then it should be a color integer and the + corresponding color will be considered transparent: all pixels with that + color value will not be drawn. (If the *palette* is specified then the *key* + is compared to the value from *palette*, not to the value directly from + *fbuf*.) + + *fbuf* can be another FrameBuffer instance, or a tuple or list of the form:: + + (buffer, width, height, format) + + or:: + + (buffer, width, height, format, stride) + + This matches the signature of the FrameBuffer constructor, and the elements + of the tuple/list are the same as the arguments to the constructor except that + the *buffer* here can be read-only. + + The *palette* argument enables blitting between FrameBuffers with differing + formats. Typical usage is to render a monochrome or grayscale glyph/icon to + a color display. The *palette* is a FrameBuffer instance whose format is + that of the current FrameBuffer. The *palette* height is one pixel and its + pixel width is the number of colors in the source FrameBuffer. The *palette* + for an N-bit source needs 2**N pixels; the *palette* for a monochrome source + would have 2 pixels representing background and foreground colors. The + application assigns a color to each pixel in the *palette*. The color of the + current pixel will be that of that *palette* pixel whose x position is the + color of the corresponding source pixel. + """ + ... + def hline(self, x: int, y: int, w: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def fill(self, c: int, /) -> None: + """ + Fill the entire FrameBuffer with the specified color. + """ + ... + def fill_rect(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + buffer: AnyWritableBuf, + width: int, + height: int, + format: int, + stride: int = ..., + /, + ) -> None: + """ + Construct a FrameBuffer object. The parameters are: + + - *buffer* is an object with a buffer protocol which must be large + enough to contain every pixel defined by the width, height and + format of the FrameBuffer. + - *width* is the width of the FrameBuffer in pixels + - *height* is the height of the FrameBuffer in pixels + - *format* specifies the type of pixel used in the FrameBuffer; + permissible values are listed under Constants below. These set the + number of bits used to encode a color value and the layout of these + bits in *buffer*. + Where a color value c is passed to a method, c is a small integer + with an encoding that is dependent on the format of the FrameBuffer. + - *stride* is the number of pixels between each horizontal line + of pixels in the FrameBuffer. This defaults to *width* but may + need adjustments when implementing a FrameBuffer within another + larger FrameBuffer or screen. The *buffer* size must accommodate + an increased step size. + + One must specify valid *buffer*, *width*, *height*, *format* and + optionally *stride*. Invalid *buffer* size or dimensions may lead to + unexpected errors. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/gc.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/gc.pyi new file mode 100644 index 000000000..026e42f51 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/gc.pyi @@ -0,0 +1,112 @@ +""" +Control the garbage collector. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/gc.html + +CPython module: :mod:`python:gc` https://docs.python.org/3/library/gc.html . + +--- +Module: 'gc' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def mem_alloc() -> int: + """ + Return the number of bytes of heap RAM that are allocated by Python code. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +def isenabled(*args, **kwargs) -> Incomplete: ... +def mem_free() -> int: + """ + Return the number of bytes of heap RAM that is available for Python + code to allocate, or -1 if this amount is not known. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +@overload +def threshold() -> int: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +@overload +def threshold(amount: int) -> None: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +def collect() -> None: + """ + Run a garbage collection. + """ + ... + +def enable() -> None: + """ + Enable automatic garbage collection. + """ + ... + +def disable() -> None: + """ + Disable automatic garbage collection. Heap memory can still be allocated, + and garbage collection can still be initiated manually using :meth:`gc.collect`. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/hashlib.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/hashlib.pyi new file mode 100644 index 000000000..072dc8874 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/hashlib.pyi @@ -0,0 +1,94 @@ +""" +Hashing algorithms. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/hashlib.html + +CPython module: :mod:`python:hashlib` https://docs.python.org/3/library/hashlib.html . + +This module implements binary data hashing algorithms. The exact inventory +of available algorithms depends on a board. Among the algorithms which may +be implemented: + +* SHA256 - The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + +* SHA1 - A previous generation algorithm. Not recommended for new usages, + but SHA1 is a part of number of Internet standards and existing + applications, so boards targeting network connectivity and + interoperability will try to provide this. + +* MD5 - A legacy algorithm, not considered cryptographically secure. Only + selected boards, targeting interoperability with legacy applications, + will offer this. + +--- +Module: 'hashlib' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, _Hash +from typing import NoReturn, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated + +class sha256(_Hash): + """ + The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + +class sha1: + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/heapq.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/heapq.pyi new file mode 100644 index 000000000..ca4ae7591 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/heapq.pyi @@ -0,0 +1,46 @@ +""" +Heap queue algorithm. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/heapq.html + +CPython module: :mod:`python:heapq` https://docs.python.org/3/library/heapq.html . + +This module implements the +`min heap queue algorithm `_. + +A heap queue is essentially a list that has its elements stored in such a way +that the first item of the list is always the smallest. + +--- +Module: 'heapq' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +def heappop(heap: list[_T], /) -> _T: + """ + Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if + ``heap`` is empty. + + The returned item will be the smallest item in the ``heap``. + """ + ... + +def heappush(heap: list[_T], item: _T, /) -> None: + """ + Push the ``item`` onto the ``heap``. + """ + ... + +def heapify(x: list[Any], /) -> None: + """ + Convert the list ``x`` into a heap. This is an in-place operation. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/machine.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/machine.pyi new file mode 100644 index 000000000..6703bbc37 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/machine.pyi @@ -0,0 +1,3052 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. + +--- +Module: 'machine' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import NoReturn, Union, List, Sequence, Optional, Callable, Tuple, overload, Any, Final +from _typeshed import Incomplete +from typing_extensions import deprecated, Awaitable, TypeAlias, TypeVar +from _mpy_shed import mp_available, _IRQ, AnyReadableBuf, AnyWritableBuf +from vfs import AbstractBlockDev + +SOFT_RESET: Final[int] = 5 +"""Reset causes.""" +PWRON_RESET: Final[int] = 1 +"""Reset causes.""" +WDT_RESET: Final[int] = 3 +"""Reset causes.""" +ID_T: TypeAlias = int | str +ATTN_0DB: int = ... +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +HARD_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +def unique_id() -> bytes: + """ + Returns a byte string with a unique identifier of a board/SoC. It will vary + from a board/SoC instance to another, if underlying hardware allows. Length + varies by hardware (so use substring of a full value if you expect a short + ID). In some MicroPython ports, ID corresponds to the network MAC address. + """ + ... + +def disable_irq() -> _IRQ_STATE: + """ + Disable interrupt requests. + Returns the previous IRQ state which should be considered an opaque value. + This return value should be passed to the `enable_irq()` function to restore + interrupts to their original state, before `disable_irq()` was called. + """ + ... + +def dht_readinto(*args, **kwargs) -> Incomplete: ... +def bitstream(pin, encoding, timing, data, /) -> Incomplete: + """ + Transmits *data* by bit-banging the specified *pin*. The *encoding* argument + specifies how the bits are encoded, and *timing* is an encoding-specific timing + specification. + + The supported encodings are: + + - ``0`` for "high low" pulse duration modulation. This will transmit 0 and + 1 bits as timed pulses, starting with the most significant bit. + The *timing* must be a four-tuple of nanoseconds in the format + ``(high_time_0, low_time_0, high_time_1, low_time_1)``. For example, + ``(400, 850, 800, 450)`` is the timing specification for WS2812 RGB LEDs + at 800kHz. + + The accuracy of the timing varies between ports. On Cortex M0 at 48MHz, it is + at best +/- 120ns, however on faster MCUs (ESP8266, ESP32, STM32, Pyboard), it + will be closer to +/-30ns. + + ``Note:`` For controlling WS2812 / NeoPixel strips, see the :mod:`neopixel` + module for a higher-level API. + """ + ... + +def bootloader(value: Optional[Any] = None) -> None: + """ + Reset the device and enter its bootloader. This is typically used to put the + device into a state where it can be programmed with new firmware. + + Some ports support passing in an optional *value* argument which can control + which bootloader to enter, what to pass to it, or other things. + """ + ... + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +def enable_irq(state: _IRQ_STATE, /) -> None: + """ + Re-enable interrupt requests. + The *state* parameter should be the value that was returned from the most + recent call to the `disable_irq()` function. + """ + ... + +def reset_cause() -> int: + """ + Get the reset cause. See :ref:`constants ` for the possible return values. + """ + ... + +def soft_reset() -> NoReturn: + """ + Performs a :ref:`soft reset ` of the interpreter, deleting all + Python objects and resetting the Python heap. + """ + ... + +def time_pulse_us(pin: Pin, pulse_level: int, timeout_us: int = 1_000_000, /) -> int: + """ + Time a pulse on the given *pin*, and return the duration of the pulse in + microseconds. The *pulse_level* argument should be 0 to time a low pulse + or 1 to time a high pulse. + + If the current input value of the pin is different to *pulse_level*, + the function first (*) waits until the pin input becomes equal to *pulse_level*, + then (**) times the duration that the pin is equal to *pulse_level*. + If the pin is already equal to *pulse_level* then timing starts straight away. + + The function will return -2 if there was timeout waiting for condition marked + (*) above, and -1 if there was timeout during the main measurement, marked (**) + above. The timeout is the same for both cases and given by *timeout_us* (which + is in microseconds). + """ + ... + +def reset() -> NoReturn: + """ + :ref:`Hard resets ` the device in a manner similar to pushing the + external RESET button. + """ + ... + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +def idle() -> None: + """ + Gates the clock to the CPU, useful to reduce power consumption at any time + during short or long periods. Peripherals continue working and execution + resumes as soon as any interrupt is triggered, or at most one millisecond + after the CPU was paused. + + It is recommended to call this function inside any tight loop that is + continuously checking for an external change (i.e. polling). This will reduce + power consumption without significantly impacting performance. To reduce + power consumption further then see the :func:`lightsleep`, + :func:`time.sleep()` and :func:`time.sleep_ms()` functions. + """ + ... + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +mem8: Incomplete ## = <8-bit memory> +"""Read/write 8 bits of memory.""" +mem32: Incomplete ## = <32-bit memory> +"""\ +Read/write 32 bits of memory. + +Use subscript notation ``[...]`` to index these objects with the address of +interest. Note that the address is the byte address, regardless of the size of +memory being accessed. + +Example use (registers are specific to an stm32 microcontroller): +""" +mem16: Incomplete ## = <16-bit memory> +"""Read/write 16 bits of memory.""" + +class LED: + def on(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class WDT: + """ + The WDT 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 machine import WDT + wdt = WDT(timeout=2000) # enable it with a timeout of 2s + wdt.feed() + + Availability of this class: pyboard, WiPy, esp8266, esp32. + """ + def timeout_ms(self, *args, **kwargs) -> Incomplete: ... + def feed(self) -> None: + """ + Feed the WDT to prevent it from resetting the system. The application + should place this call in a sensible place ensuring that the WDT is + only fed after verifying that everything is functioning correctly. + """ + ... + def __init__(self, *, id: int = 0, timeout: int = 5000) -> None: + """ + Create a WDT object and start it. The timeout must be given in milliseconds. + Once it is running the timeout cannot be changed and the WDT cannot be stopped either. + + Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout + cannot be specified, it is determined by the underlying system. + """ + +class I2S: + """ + I2S is a synchronous serial protocol used to connect digital audio devices. + At the physical level, a bus consists of 3 lines: SCK, WS, SD. + The I2S class supports controller operation. Peripheral operation is not supported. + + The I2S class is currently available as a Technical Preview. During the preview period, feedback from + users is encouraged. Based on this feedback, the I2S class API and implementation may be changed. + + I2S objects can be created and initialized using:: + + from machine import I2S + from machine import Pin + + # ESP32 + sck_pin = Pin(14) # Serial clock output + ws_pin = Pin(13) # Word clock output + sd_pin = Pin(12) # Serial data output + + or + + # PyBoards + sck_pin = Pin("Y6") # Serial clock output + ws_pin = Pin("Y5") # Word clock output + sd_pin = Pin("Y8") # Serial data output + + audio_out = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.TX, + bits=16, + format=I2S.MONO, + rate=44100, + ibuf=20000) + + audio_in = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.RX, + bits=32, + format=I2S.STEREO, + rate=22050, + ibuf=20000) + + 3 modes of operation are supported: + - blocking + - non-blocking + - uasyncio + + blocking:: + + num_written = audio_out.write(buf) # blocks until buf emptied + + num_read = audio_in.readinto(buf) # blocks until buf filled + + non-blocking:: + + audio_out.irq(i2s_callback) # i2s_callback is called when buf is emptied + num_written = audio_out.write(buf) # returns immediately + + audio_in.irq(i2s_callback) # i2s_callback is called when buf is filled + num_read = audio_in.readinto(buf) # returns immediately + + uasyncio:: + + swriter = uasyncio.StreamWriter(audio_out) + swriter.write(buf) + await swriter.drain() + + sreader = uasyncio.StreamReader(audio_in) + num_read = await sreader.readinto(buf) + """ + + RX: Final[int] = 0 + """for initialising the I2S bus ``mode`` to receive""" + MONO: Final[int] = 0 + """for initialising the I2S bus ``format`` to mono""" + STEREO: Final[int] = 1 + """for initialising the I2S bus ``format`` to stereo""" + TX: Final[int] = 1 + """for initialising the I2S bus ``mode`` to transmit""" + @staticmethod + def shift( + buf: AnyWritableBuf, + bits: int, + shift: int, + /, + ) -> None: + """ + bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample. + Positive for left shift, negative for right shift. + Typically used for volume control. Each bit shift changes sample volume by 6dB. + """ + ... + def init( + self, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + see Constructor for argument descriptions + """ + ... + def irq( + self, + handler: Callable[[Any], None], + /, + ) -> None: + """ + Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method). + Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation. + ``handler`` is called in the context of the MicroPython scheduler. + """ + ... + def readinto( + self, + buf: AnyWritableBuf, + /, + ) -> int: + """ + Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the left channel sample data is used. + Returns number of bytes read + """ + ... + def deinit(self) -> None: + """ + Deinitialize the I2S bus + """ + ... + def write( + self, + buf: AnyReadableBuf, + /, + ) -> int: + """ + Write audio samples contained in ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the sample data is written to both the right and left channels. + Returns number of bytes written + """ + ... + def __init__( + self, + id: ID_T, + /, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + Construct an I2S object of the given id: + + - ``id`` identifies a particular I2S bus. + + ``id`` is board and port specific: + + - PYBv1.0/v1.1: has one I2S bus with id=2. + - PYBD-SFxW: has two I2S buses with id=1 and id=2. + - ESP32: has two I2S buses with id=0 and id=1. + + Keyword-only parameters that are supported on all ports: + + - ``sck`` is a pin object for the serial clock line + - ``ws`` is a pin object for the word select line + - ``sd`` is a pin object for the serial data line + - ``mode`` specifies receive or transmit + - ``bits`` specifies sample size (bits), 16 or 32 + - ``format`` specifies channel format, STEREO or MONO + - ``rate`` specifies audio sampling rate (samples/s) + - ``ibuf`` specifies internal buffer length (bytes) + + For all ports, DMA runs continuously in the background and allows user applications to perform other operations while + sample data is transfered between the internal buffer and the I2S peripheral unit. + Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations + before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method). + """ + +class ADC: + """ + The ADC class provides an interface to analog-to-digital convertors, and + represents a single endpoint that can sample a continuous voltage and + convert it to a discretised value. + + Example usage:: + + import machine + + adc = machine.ADC(pin) # create an ADC object acting on a pin + val = adc.read_u16() # read a raw analog value in the range 0-65535 + """ + + VREF: int = ... + CORE_VREF: int = ... + CORE_VBAT: int = ... + CORE_TEMP: int = ... + ATTN_0DB: int = 0 + ATTN_2_5DB: int = 1 + ATTN_6DB: int = 2 + ATTN_11DB: int = 3 + WIDTH_9BIT: int = 9 + WIDTH_10BIT: int = 10 + WIDTH_11BIT: int = 11 + WIDTH_12BIT: int = 12 + def read_uv(self) -> int: + """ + Take an analog reading and return an integer value with units of + microvolts. It is up to the particular port whether or not this value + is calibrated, and how calibration is done. + """ + ... + def read_u16(self) -> int: + """ + Take an analog reading and return an integer in the range 0-65535. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 65535. + """ + ... + def __init__(self, pin: PinLike, *, atten=ATTN_0DB) -> None: + """ + Access the ADC associated with a source identified by *id*. This + *id* may be an integer (usually specifying a channel number), a + :ref:`Pin ` object, or other value supported by the + underlying machine. + .. note:: + + WiPy has a custom implementation of ADC, see ADCWiPy for details. + + on ESP32 : `atten` specifies the attenuation level for the ADC input. + """ + + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class I2C: + """ + 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. + + I2C objects are created attached to a specific bus. They can be initialised + when created, or initialised later on. + + Printing the I2C object gives you information about its configuration. + + Both hardware and software I2C implementations exist via the + :ref:`machine.I2C ` and `machine.SoftI2C` classes. Hardware I2C uses + underlying hardware support of the system to perform the reads/writes and is + usually efficient and fast but may have restrictions on which pins can be used. + Software I2C is implemented by bit-banging and can be used on any pin but is not + as efficient. These classes have the same methods available and differ primarily + in the way they are constructed. + + Example usage:: + + from machine import I2C + + i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz + # depending on the port, extra parameters may be required + # to select the peripheral and/or pins to use + + i2c.scan() # scan for peripherals, returning a list of 7-bit addresses + + i2c.writeto(42, b'123') # write 3 bytes to peripheral with 7-bit address 42 + i2c.readfrom(42, 4) # read 4 bytes from peripheral with 7-bit address 42 + + i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of peripheral 42, + # starting at memory-address 8 in the peripheral + i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42 + # starting at address 2 in the peripheral + """ + def readfrom_mem_into(self, addr: int, memaddr: int, buf: AnyWritableBuf, /, *, addrsize: int = 8) -> None: + """ + Read into *buf* from the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. The number of bytes read is the + length of *buf*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def readfrom_into(self, addr: int, buf: AnyWritableBuf, stop: bool = True, /) -> None: + """ + Read into *buf* from the peripheral specified by *addr*. + The number of bytes read will be the length of *buf*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + + The method returns ``None``. + """ + ... + def readfrom_mem(self, addr: int, memaddr: int, nbytes: int, /, *, addrsize: int = 8) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr* starting from the memory + address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits. + Returns a `bytes` object with the data read. + """ + ... + def writeto_mem(self, addr: int, memaddr: int, buf: AnyReadableBuf, /, *, addrsize: int = 8) -> None: + """ + Write *buf* to the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def scan(self) -> List: + """ + 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 write bit) is sent on the bus. + """ + ... + def writeto(self, addr: int, buf: AnyReadableBuf, stop: bool = True, /) -> int: + """ + Write the bytes from *buf* to the peripheral specified by *addr*. If a + NACK is received following the write of a byte from *buf* then the + remaining bytes are not sent. If *stop* is true then a STOP condition is + generated at the end of the transfer, even if a NACK is received. + The function returns the number of ACKs that were received. + """ + ... + def writevto(self, addr: int, vector: Sequence[AnyReadableBuf], stop: bool = True, /) -> int: + """ + Write the bytes contained in *vector* to the peripheral specified by *addr*. + *vector* should be a tuple or list of objects with the buffer protocol. + The *addr* is sent once and then the bytes from each object in *vector* + are written out sequentially. The objects in *vector* may be zero bytes + in length in which case they don't contribute to the output. + + If a NACK is received following the write of a byte from one of the + objects in *vector* then the remaining bytes, and any remaining objects, + are not sent. If *stop* is true then a STOP condition is generated at + the end of the transfer, even if a NACK is received. The function + returns the number of ACKs that were received. + """ + ... + def start(self) -> None: + """ + Generate a START condition on the bus (SDA transitions to low while SCL is high). + """ + ... + def readfrom(self, addr: int, nbytes: int, stop: bool = True, /) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + Returns a `bytes` object with the data read. + """ + ... + def readinto(self, buf: AnyWritableBuf, nack: bool = True, /) -> None: + """ + Reads bytes from the bus and stores them into *buf*. The number of bytes + read is the length of *buf*. An ACK will be sent on the bus after + receiving all but the last byte. After the last byte is received, if *nack* + is true then a NACK will be sent, otherwise an ACK will be sent (and in this + case the peripheral assumes more bytes are going to be read in a later call). + """ + ... + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + def stop(self) -> None: + """ + Generate a STOP condition on the bus (SDA transitions to high while SCL is high). + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes from *buf* to the bus. Checks that an ACK is received + after each byte and stops transmitting the remaining bytes if a NACK is + received. The function returns the number of ACKs that were received. + """ + ... + + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class I2CTarget: + """ + Construct and return a new I2CTarget object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values depend on the + particular port/board. Some ports have a default in which case this parameter + can be omitted. + - *addr* is the I2C address of the target. + - *addrsize* is the number of bits in the I2C target address. Valid values + are 7 and 10. + - *mem* is an object with the buffer protocol that is writable. If not + specified then there is no backing memory and data must be read/written + using the :meth:`I2CTarget.readinto` and :meth:`I2CTarget.write` methods. + - *mem_addrsize* is the number of bits in the memory address. Valid values + are 0, 8, 16, 24 and 32. + - *scl* is a pin object specifying the pin to use for SCL. + - *sda* is a pin object specifying the pin to use for SDA. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + IRQ_END_READ: Final[int] = 16 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_WRITE: Final[int] = 2 + """IRQ trigger sources.""" + IRQ_END_WRITE: Final[int] = 32 + """IRQ trigger sources.""" + IRQ_READ_REQ: Final[int] = 4 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_READ: Final[int] = 1 + """IRQ trigger sources.""" + IRQ_WRITE_REQ: Final[int] = 8 + """IRQ trigger sources.""" + def deinit(self) -> Incomplete: + """ + Deinitialise the I2C target. After this method is called the hardware will no + longer respond to requests on the I2C bus, and no other methods can be called. + """ + ... + def irq(self, handler=None, trigger=IRQ_END_READ | IRQ_END_WRITE, hard=False) -> Incomplete: + """ + Configure an IRQ *handler* to be called when an event occurs. The possible events are + given by the following constants, which can be or'd together and passed to the *trigger* + argument: + + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a read transaction. + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a write transaction. + - ``IRQ_READ_REQ`` indicates that the controller is requesting data, and this + request must be satisfied by calling `I2CTarget.write` with the data to be + passed back to the controller. + - ``IRQ_WRITE_REQ`` indicates that the controller has written data, and the + data must be read by calling `I2CTarget.readinto`. + - ``IRQ_END_READ`` indicates that the controller has finished a read transaction. + - ``IRQ_END_WRITE`` indicates that the controller has finished a write transaction. + + Not all triggers are available on all ports. If a port has the constant then that + event is available. + + Note the following restrictions: + + - ``IRQ_ADDR_MATCH_READ``, ``IRQ_ADDR_MATCH_READ``, ``IRQ_READ_REQ`` and + ``IRQ_WRITE_REQ`` must be handled by a hard IRQ callback (with the *hard* argument + set to ``True``). This is because these events have very strict timing requirements + and must usually be satisfied synchronously with the hardware event. + + - ``IRQ_END_READ`` and ``IRQ_END_WRITE`` may be handled by either a soft or hard + IRQ callback (although note that all events must be registered with the same handler, + so if any events need a hard callback then all events must be hard). + + - If a memory buffer has been supplied in the constructor then ``IRQ_END_WRITE`` + is not emitted for the transaction that writes the memory address. This is to + allow ``IRQ_END_READ`` and ``IRQ_END_WRITE`` to function correctly as soft IRQ + callbacks, where the IRQ handler may be called quite some time after the actual + hardware event. + """ + ... + def write(self, buf) -> int: + """ + Write out the bytes from the given buffer, to be passed to the I2C controller + after it sends a read request. Returns the number of bytes written. Most ports + only accept one byte at a time to this method. + """ + ... + def readinto(self, buf) -> int: + """ + Read into the given buffer any pending bytes written by the I2C controller. + Returns the number of bytes read. + """ + ... + def __init__(self, id, addr, *, addrsize=7, mem=None, mem_addrsize=8, scl=None, sda=None) -> None: ... + +class SoftI2C(I2C): + """ + Construct a new software I2C object. The parameters are: + + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + - *timeout* is the maximum time in microseconds to wait for clock + stretching (SCL held low by another device on the bus), after + which an ``OSError(ETIMEDOUT)`` exception is raised. + """ + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, scl, sda, *, freq=400000, timeout=50000) -> None: ... + +class SoftSPI(SPI): + """ + Construct a new software SPI object. Additional parameters must be + given, usually at least *sck*, *mosi* and *miso*, and these are used + to initialise the bus. See `SPI.init` for a description of the parameters. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + baudrate=500000, + *, + polarity=0, + phase=0, + bits=8, + firstbit=MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: ... + +class Timer: + """ + Hardware timers deal with timing of periods and events. Timers are perhaps + the most flexible and heterogeneous kind of hardware in MCUs and SoCs, + differently greatly from a model to a model. MicroPython's Timer class + defines a baseline operation of executing a callback with a given period + (or once after some delay), and allow specific boards to define more + non-standard behaviour (which thus won't be portable to other boards). + + See discussion of :ref:`important constraints ` on + Timer callbacks. + + .. note:: + + Memory can't be allocated inside irq handlers (an interrupt) and so + exceptions raised within a handler don't give much information. See + :func:`micropython.alloc_emergency_exception_buf` for how to get around this + limitation. + + If you are using a WiPy board please refer to :ref:`machine.TimerWiPy ` + instead of this class. + """ + + PERIODIC: Final[int] = 2 + """Timer operating mode.""" + ONE_SHOT: Final[int] = 1 + """Timer operating mode.""" + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + def deinit(self) -> None: + """ + Deinitialises the timer. Stops the timer, and disables the timer peripheral. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + +class UART: + """ + UART implements the standard UART/USART duplex serial communications protocol. At + the physical level it consists of 2 lines: RX and TX. The unit of communication + is a character (not to be confused with a string character) which can be 8 or 9 + bits wide. + + UART objects can be created and initialised using:: + + from machine import UART + + uart = UART(1, 9600) # init with given baudrate + uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters + + Supported parameters differ on a board: + + Pyboard: Bits can be 7, 8 or 9. Stop can be 1 or 2. With *parity=None*, + only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits + are supported. + + WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2. + + A UART object acts like a `stream` object and reading and writing is done + using the standard stream methods:: + + uart.read(10) # read 10 characters, returns a bytes object + uart.read() # read all available characters + uart.readline() # read a line + uart.readinto(buf) # read and store into the given buffer + uart.write('abc') # write the 3 characters + """ + + INV_TX: Final[int] = 1 + INV_RX: Final[int] = 2 + CTS: Final[int] = 2 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RXIDLE: Final[int] = 1 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + IRQ_TXIDLE: Final[int] = 2 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + RTS: Final[int] = 1 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RX: Incomplete + IRQ_BREAK: Incomplete + IDLE: int = ... + def irq( + self, + handler: Callable[[UART], None] | None = None, + trigger: int = 0, + hard: bool = False, + /, + ) -> _IRQ: + """ + Configure an interrupt handler to be called when a UART event occurs. + + The arguments are: + + - *handler* is an optional function to be called when the interrupt event + triggers. The handler must take exactly one argument which is the + ``UART`` instance. + + - *trigger* configures the event(s) which can generate an interrupt. + Possible values are a mask of one or more of the following: + + - ``UART.IRQ_RXIDLE`` interrupt after receiving at least one character + and then the RX line goes idle. + - ``UART.IRQ_RX`` interrupt after each received character. + - ``UART.IRQ_TXIDLE`` interrupt after or while the last character(s) of + a message are or have been sent. + - ``UART.IRQ_BREAK`` interrupt when a break state is detected at RX + + - *hard* if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + + Returns an irq object. + + Due to limitations of the hardware not all trigger events are available on all ports. + """ + ... + def sendbreak(self) -> None: + """ + Send a break condition on the bus. This drives the bus low for a duration + longer than required for a normal transmission of a character. + """ + ... + def deinit(self) -> None: + """ + Turn off the UART bus. + + .. note:: + You will not be able to call ``init()`` on the object after ``deinit()``. + A new instance needs to be created in that case. + """ + ... + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + def flush(self) -> Incomplete: + """ + Waits until all data has been sent. In case of a timeout, an exception is raised. The timeout + duration depends on the tx buffer size and the baud rate. Unless flow control is enabled, a timeout + should not occur. + + .. note:: + + For the esp8266 and nrf ports the call returns while the last byte is sent. + If required, a one character wait time has to be added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + def txdone(self) -> bool: + """ + Tells whether all data has been sent or no data transfer is happening. In this case, + it returns ``True``. If a data transmission is ongoing it returns ``False``. + + .. note:: + + For the esp8266 and nrf ports the call may return ``True`` even if the last byte + of a transfer is still being sent. If required, a one character wait time has to be + added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read without + blocking. It will return 0 if there are no characters available and a positive + number if there are characters. The method may return 1 even if there is more + than one character available for reading. + + For more sophisticated querying of available characters use select.poll:: + + poll = select.poll() + poll.register(uart, select.POLLIN) + poll.poll(timeout) + """ + ... + def write(self, buf: AnyReadableBuf, /) -> Union[int, None]: + """ + Write the buffer of bytes to the bus. + + Return value: number of bytes written or ``None`` on timeout. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + def readline(self) -> Union[str, None]: + """ + Read a line, ending in a newline character. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: the line read or ``None`` on timeout. + """ + ... + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + +class PWM: + """ + This class provides pulse width modulation output. + + Example usage:: + + from machine import PWM + + pwm = PWM(pin) # create a PWM object on a pin + pwm.duty_u16(32768) # set duty to 50% + + # reinitialise with a period of 200us, duty of 5us + pwm.init(freq=5000, duty_ns=5000) + + pwm.duty_ns(3000) # set pulse width to 3us + + pwm.deinit() + + + Limitations of PWM + ------------------ + + * Not all frequencies can be generated with absolute accuracy due to + the discrete nature of the computing hardware. Typically the PWM frequency + is obtained by dividing some integer base frequency by an integer divider. + For example, if the base frequency is 80MHz and the required PWM frequency is + 300kHz the divider must be a non-integer number 80000000 / 300000 = 266.67. + After rounding the divider is set to 267 and the PWM frequency will be + 80000000 / 267 = 299625.5 Hz, not 300kHz. If the divider is set to 266 then + the PWM frequency will be 80000000 / 266 = 300751.9 Hz, but again not 300kHz. + + * The duty cycle has the same discrete nature and its absolute accuracy is not + achievable. On most hardware platforms the duty will be applied at the next + frequency period. Therefore, you should wait more than "1/frequency" before + measuring the duty. + + * The frequency and the duty cycle resolution are usually interdependent. + The higher the PWM frequency the lower the duty resolution which is available, + and vice versa. For example, a 300kHz PWM frequency can have a duty cycle + resolution of 8 bit, not 16-bit as may be expected. In this case, the lowest + 8 bits of *duty_u16* are insignificant. So:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2) + + and:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255) + + will generate PWM with the same 50% duty cycle. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + def init(self, *, freq: int = ..., duty_u16: int = ..., duty_ns: int = ...) -> None: + """ + Modify settings for the PWM object. See the above constructor for details + about the parameters. + """ + ... + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + def deinit(self) -> None: + """ + Disable the PWM output. + """ + ... + def __init__( + self, + dest: PinLike, + /, + *, + freq: int = ..., + duty_u16: int = ..., + duty_ns: int = ..., + ) -> None: + """ + Construct and return a new PWM object using the following parameters: + + - *dest* is the entity on which the PWM is output, which is usually a + :ref:`machine.Pin ` object, but a port may allow other values, + like integers. + - *freq* should be an integer which sets the frequency in Hz for the + PWM cycle. + - *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``. + - *duty_ns* sets the pulse width in nanoseconds. + + Setting *freq* may affect other PWM objects if the objects share the same + underlying PWM generator (this is hardware specific). + Only one of *duty_u16* and *duty_ns* should be specified at a time. + """ + +class Signal(Pin): + """ + The Signal class is a simple extension of the `Pin` class. Unlike Pin, which + can be only in "absolute" 0 and 1 states, a Signal can be in "asserted" + (on) or "deasserted" (off) states, while being inverted (active-low) or + not. In other words, it adds logical inversion support to Pin functionality. + While this may seem a simple addition, it is exactly what is needed to + support wide array of simple digital devices in a way portable across + different boards, which is one of the major MicroPython goals. Regardless + of whether different users have an active-high or active-low LED, a normally + open or normally closed relay - you can develop a single, nicely looking + application which works with each of them, and capture hardware + configuration differences in few lines in the config file of your app. + + Example:: + + from machine import Pin, Signal + + # Suppose you have an active-high LED on pin 0 + led1_pin = Pin(0, Pin.OUT) + # ... and active-low LED on pin 1 + led2_pin = Pin(1, Pin.OUT) + + # Now to light up both of them using Pin class, you'll need to set + # them to different values + led1_pin.value(1) + led2_pin.value(0) + + # Signal class allows to abstract away active-high/active-low + # difference + led1 = Signal(led1_pin, invert=False) + led2 = Signal(led2_pin, invert=True) + + # Now lighting up them looks the same + led1.value(1) + led2.value(1) + + # Even better: + led1.on() + led2.on() + + Following is the guide when Signal vs Pin should be used: + + * Use Signal: If you want to control a simple on/off (including software + PWM!) devices like LEDs, multi-segment indicators, relays, buzzers, or + read simple binary sensors, like normally open or normally closed buttons, + pulled high or low, Reed switches, moisture/flame detectors, etc. etc. + Summing up, if you have a real physical device/sensor requiring GPIO + access, you likely should use a Signal. + + * Use Pin: If you implement a higher-level protocol or bus to communicate + with more complex devices. + + The split between Pin and Signal come from the use cases above and the + architecture of MicroPython: Pin offers the lowest overhead, which may + be important when bit-banging protocols. But Signal adds additional + flexibility on top of Pin, at the cost of minor overhead (much smaller + than if you implemented active-high vs active-low device differences in + Python manually!). Also, Pin is a low-level object which needs to be + implemented for each support board, while Signal is a high-level object + which comes for free once Pin is implemented. + + If in doubt, give the Signal a try! Once again, it is offered to save + developers from the need to handle unexciting differences like active-low + vs active-high signals, and allow other users to share and enjoy your + application, instead of being frustrated by the fact that it doesn't + work for them simply because their LEDs or relays are wired in a slightly + different way. + """ + def off(self) -> None: + """ + Deactivate signal. + """ + ... + def on(self) -> None: + """ + Activate signal. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + +class Pin: + """ + A pin object is used to control I/O pins (also known as GPIO - general-purpose + input/output). Pin objects are commonly associated with a physical pin that can + drive an output voltage and read input voltages. The pin class has methods to set the mode of + the pin (IN, OUT, etc) and methods to get and set the digital logic level. + For analog control of a pin, see the :class:`ADC` class. + + A pin object is constructed by using an identifier which unambiguously + specifies a certain I/O pin. The allowed forms of the identifier and the + physical pin that the identifier maps to are port-specific. Possibilities + for the identifier are an integer, a string or a tuple with port and pin + number. + + Usage Model:: + + from machine import Pin + + # create an output pin on pin #0 + p0 = Pin(0, Pin.OUT) + + # set the value low then high + p0.value(0) + p0.value(1) + + # create an input pin on pin #2, with a pull up resistor + p2 = Pin(2, Pin.IN, Pin.PULL_UP) + + # read and print the pin value + print(p2.value()) + + # reconfigure pin #0 in input mode with a pull down resistor + p0.init(p0.IN, p0.PULL_DOWN) + + # configure an irq callback + p0.irq(lambda p:print(p)) + """ + + OPEN_DRAIN: Final[int] = 2 + """Selects the pin mode.""" + IRQ_RISING: Final[int] = 1 + """Selects the IRQ trigger type.""" + IRQ_FALLING: Final[int] = 2 + """Selects the IRQ trigger type.""" + IN: Final[int] = 0 + """Selects the pin mode.""" + PULL_UP_22K: Final[int] = 3 + OUT: Final[int] = 1 + """Selects the pin mode.""" + PULL_UP: Final[int] = 2 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_HOLD: Final[int] = 5 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_DOWN: Final[int] = 0 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + DRIVE_2: Final[int] = 3 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_1: Final[int] = 2 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_0: Final[int] = 1 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + PULL_UP_47K: Final[int] = 1 + DRIVE_OFF: Final[int] = 0 + DRIVE_3: Final[int] = 4 + DRIVE_6: Final[int] = 7 + DRIVE_5: Final[int] = 6 + DRIVE_4: Final[int] = 5 + ALT: Incomplete + ALT_OPEN_DRAIN: Incomplete + ANALOG: Incomplete + IRQ_LOW_LEVEL: Incomplete + IRQ_HIGH_LEVEL: Incomplete + def low(self) -> None: + """ + Set pin to "0" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + def irq( + self, + /, + handler: Callable[[Pin], None] | None = None, + trigger: int = (IRQ_FALLING | IRQ_RISING), + *, + priority: int = 1, + wake: int | None = None, + hard: bool = False, + ) -> Callable[..., Incomplete]: + """ + Configure an interrupt handler to be called when the trigger source of the + pin is active. If the pin mode is ``Pin.IN`` then the trigger source is + the external value on the pin. If the pin mode is ``Pin.OUT`` then the + trigger source is the output buffer of the pin. Otherwise, if the pin mode + is ``Pin.OPEN_DRAIN`` then the trigger source is the output buffer for + state '0' and the external pin value for state '1'. + + The arguments are: + + - ``handler`` is an optional function to be called when the interrupt + triggers. The handler must take exactly one argument which is the + ``Pin`` instance. + + - ``trigger`` configures the event which can generate an interrupt. + Possible values are: + + - ``Pin.IRQ_FALLING`` interrupt on falling edge. + - ``Pin.IRQ_RISING`` interrupt on rising edge. + - ``Pin.IRQ_LOW_LEVEL`` interrupt on low level. + - ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level. + + These values can be OR'ed together to trigger on multiple events. + + - ``priority`` sets the priority level of the interrupt. The values it + can take are port-specific, but higher values always represent higher + priorities. + + - ``wake`` selects the power mode in which this interrupt can wake up the + system. It can be ``machine.IDLE``, ``machine.SLEEP`` or ``machine.DEEPSLEEP``. + These values can also be OR'ed together to make a pin generate interrupts in + more than one power mode. + + - ``hard`` if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + Not all ports support this argument. + + This method returns a callback object. + + The following methods are not part of the core Pin API and only implemented on certain ports. + """ + ... + def toggle(self) -> Incomplete: + """ + Toggle output pin from "0" to "1" or vice-versa. + + Availability: cc3200, esp32, esp8266, mimxrt, rp2, samd ports. + """ + ... + def off(self) -> None: + """ + Set pin to "0" output level. + """ + ... + def on(self) -> None: + """ + Set pin to "1" output level. + """ + ... + def init( + self, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Re-initialise the pin using the given parameters. Only those arguments that + are specified will be set. The rest of the pin peripheral state will remain + unchanged. See the constructor documentation for details of the arguments. + + Returns ``None``. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + def high(self) -> None: + """ + Set pin to "1" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + + class cpu: + GPIO_SD_00: Pin ## = Pin(GPIO_SD_00) + GPIO_AD_14: Pin ## = Pin(GPIO_AD_14) + GPIO_AD_13: Pin ## = Pin(GPIO_AD_13) + GPIO_SD_01: Pin ## = Pin(GPIO_SD_01) + GPIO_SD_02: Pin ## = Pin(GPIO_SD_02) + PMIC_ON_REQ: Pin ## = Pin(PMIC_ON_REQ) + GPIO_AD_09: Pin ## = Pin(GPIO_AD_09) + GPIO_AD_08: Pin ## = Pin(GPIO_AD_08) + GPIO_AD_12: Pin ## = Pin(GPIO_AD_12) + GPIO_AD_10: Pin ## = Pin(GPIO_AD_10) + GPIO_AD_11: Pin ## = Pin(GPIO_AD_11) + GPIO_SD_11: Pin ## = Pin(GPIO_SD_11) + GPIO_SD_10: Pin ## = Pin(GPIO_SD_10) + GPIO_SD_09: Pin ## = Pin(GPIO_SD_09) + GPIO_SD_12: Pin ## = Pin(GPIO_SD_12) + GPIO_SD_13: Pin ## = Pin(GPIO_SD_13) + GPIO_SD_03: Pin ## = Pin(GPIO_SD_03) + GPIO_SD_05: Pin ## = Pin(GPIO_SD_05) + GPIO_SD_04: Pin ## = Pin(GPIO_SD_04) + GPIO_SD_08: Pin ## = Pin(GPIO_SD_08) + GPIO_SD_06: Pin ## = Pin(GPIO_SD_06) + GPIO_SD_07: Pin ## = Pin(GPIO_SD_07) + GPIO_07: Pin ## = Pin(GPIO_07) + GPIO_06: Pin ## = Pin(GPIO_06) + GPIO_05: Pin ## = Pin(GPIO_05) + GPIO_08: Pin ## = Pin(GPIO_08) + GPIO_09: Pin ## = Pin(GPIO_09) + GPIO_AD_07: Pin ## = Pin(GPIO_AD_07) + GPIO_01: Pin ## = Pin(GPIO_01) + GPIO_00: Pin ## = Pin(GPIO_00) + GPIO_04: Pin ## = Pin(GPIO_04) + GPIO_02: Pin ## = Pin(GPIO_02) + GPIO_03: Pin ## = Pin(GPIO_03) + GPIO_AD_04: Pin ## = Pin(GPIO_AD_04) + GPIO_AD_03: Pin ## = Pin(GPIO_AD_03) + GPIO_AD_02: Pin ## = Pin(GPIO_AD_02) + GPIO_AD_05: Pin ## = Pin(GPIO_AD_05) + GPIO_AD_06: Pin ## = Pin(GPIO_AD_06) + GPIO_10: Pin ## = Pin(GPIO_10) + GPIO_12: Pin ## = Pin(GPIO_12) + GPIO_11: Pin ## = Pin(GPIO_11) + GPIO_AD_01: Pin ## = Pin(GPIO_AD_01) + GPIO_13: Pin ## = Pin(GPIO_13) + GPIO_AD_00: Pin ## = Pin(GPIO_AD_00) + def __init__(self, *argv, **kwargs) -> None: ... + + class board: + LED_GREEN: Pin ## = Pin(GPIO_11) + ENC_B: Pin ## = Pin(GPIO_AD_06) + PWM_AT: Pin ## = Pin(GPIO_02) + MCK: Pin ## = Pin(GPIO_08) + PWM_AB: Pin ## = Pin(GPIO_01) + D7: Pin ## = Pin(GPIO_AD_02) + D6: Pin ## = Pin(GPIO_AD_01) + ENC_A: Pin ## = Pin(GPIO_AD_05) + D8: Pin ## = Pin(GPIO_SD_02) + D9: Pin ## = Pin(GPIO_03) + D5: Pin ## = Pin(GPIO_01) + SD_TX: Pin ## = Pin(GPIO_04) + SD_RX: Pin ## = Pin(GPIO_03) + PWM_BB: Pin ## = Pin(GPIO_03) + VOLT_DCB: Pin ## = Pin(GPIO_AD_09) + WS_RX: Pin ## = Pin(GPIO_02) + PWM_CB: Pin ## = Pin(GPIO_05) + PWM_BT: Pin ## = Pin(GPIO_04) + SCK_TX: Pin ## = Pin(GPIO_06) + PWM_CT: Pin ## = Pin(GPIO_06) + SCK_RX: Pin ## = Pin(GPIO_01) + WS_TX: Pin ## = Pin(GPIO_07) + CUR_A: Pin ## = Pin(GPIO_AD_01) + A5: Pin ## = Pin(GPIO_AD_02) + CUR_DCB: Pin ## = Pin(GPIO_AD_10) + CUR_B: Pin ## = Pin(GPIO_AD_02) + CUR_C: Pin ## = Pin(GPIO_AD_07) + A1: Pin ## = Pin(GPIO_AD_09) + A0: Pin ## = Pin(GPIO_AD_07) + A4: Pin ## = Pin(GPIO_AD_01) + A2: Pin ## = Pin(GPIO_AD_10) + A3: Pin ## = Pin(GPIO_AD_14) + D4: Pin ## = Pin(GPIO_08) + D15: Pin ## = Pin(GPIO_02) + D14: Pin ## = Pin(GPIO_01) + D0: Pin ## = Pin(GPIO_09) + D2: Pin ## = Pin(GPIO_AD_05) + D3: Pin ## = Pin(GPIO_AD_06) + D10: Pin ## = Pin(GPIO_AD_05) + D1: Pin ## = Pin(GPIO_10) + D13: Pin ## = Pin(GPIO_AD_06) + D11: Pin ## = Pin(GPIO_AD_04) + D12: Pin ## = Pin(GPIO_AD_03) + def __init__(self, *argv, **kwargs) -> None: ... + + def __init__( + self, + id: Any, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Access the pin peripheral (GPIO pin) associated with the given ``id``. If + additional arguments are given in the constructor then they are used to initialise + the pin. Any settings that are not specified will remain in their previous state. + + The arguments are: + + - ``id`` is mandatory and can be an arbitrary object. Among possible value + types are: int (an internal Pin identifier), str (a Pin name), and tuple + (pair of [port, pin]). + + - ``mode`` specifies the pin mode, which can be one of: + + - ``Pin.IN`` - Pin is configured for input. If viewed as an output the pin + is in high-impedance state. + + - ``Pin.OUT`` - Pin is configured for (normal) output. + + - ``Pin.OPEN_DRAIN`` - Pin is configured for open-drain output. Open-drain + output works in the following way: if the output value is set to 0 the pin + is active at a low level; if the output value is 1 the pin is in a high-impedance + state. Not all ports implement this mode, or some might only on certain pins. + + - ``Pin.ALT`` - Pin is configured to perform an alternative function, which is + port specific. For a pin configured in such a way any other Pin methods + (except :meth:`Pin.init`) are not applicable (calling them will lead to undefined, + or a hardware-specific, result). Not all ports implement this mode. + + - ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as + open-drain. Not all ports implement this mode. + + - ``Pin.ANALOG`` - Pin is configured for analog input, see the :class:`ADC` class. + + - ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be + one of: + + - ``None`` - No pull up or down resistor. + - ``Pin.PULL_UP`` - Pull up resistor enabled. + - ``Pin.PULL_DOWN`` - Pull down resistor enabled. + + - ``value`` is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and specifies initial + output pin value if given, otherwise the state of the pin peripheral remains + unchanged. + + - ``drive`` specifies the output power of the pin and can be one of: ``Pin.LOW_POWER``, + ``Pin.MED_POWER`` or ``Pin.HIGH_POWER``. The actual current driving capabilities + are port dependent. Not all ports implement this argument. + + - ``alt`` specifies an alternate function for the pin and the values it can take are + port dependent. This argument is valid only for ``Pin.ALT`` and ``Pin.ALT_OPEN_DRAIN`` + modes. It may be used when a pin supports more than one alternate function. If only + one pin alternate function is supported the this argument is not required. Not all + ports implement this argument. + + As specified above, the Pin class allows to set an alternate function for a particular + pin, but it does not specify any further operations on such a pin. Pins configured in + alternate-function mode are usually not used as GPIO but are instead driven by other + hardware peripherals. The only operation supported on such a pin is re-initialising, + by calling the constructor or :meth:`Pin.init` method. If a pin that is configured in + alternate-function mode is re-initialised with ``Pin.IN``, ``Pin.OUT``, or + ``Pin.OPEN_DRAIN``, the alternate function will be removed from the pin. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class RTC: + """ + The RTC is an independent clock that keeps track of the date + and time. + + Example usage:: + + rtc = machine.RTC() + rtc.datetime((2020, 1, 21, 2, 10, 32, 36, 0)) + print(rtc.datetime()) + + + + The documentation for RTC is in a poor state;1 + """ + + ALARM0: Final[int] = 0 + """irq trigger source""" + def irq( + self, + /, + *, + trigger: int, + handler: Callable[[RTC], None] | None = None, + wake: int = IDLE, + ) -> None: + """ + Create an irq object triggered by a real time clock alarm. + + - ``trigger`` must be ``RTC.ALARM0`` + - ``handler`` is the function to be called when the callback is triggered. + - ``wake`` specifies the sleep mode from where this interrupt can wake + up the system. + """ + ... + def cancel(self, *args, **kwargs) -> Incomplete: ... + def datetime(self, datetimetuple: Any | None = None) -> Tuple: + """ + Get or set the date and time of the RTC. + + With no arguments, this method returns an 8-tuple with the current + date and time. With 1 argument (being an 8-tuple) it sets the date + and time. + + The 8-tuple has the following format: + + (year, month, day, weekday, hours, minutes, seconds, subseconds) + + The meaning of the ``subseconds`` field is hardware dependent. + """ + ... + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + def calibration(self, *args, **kwargs) -> Incomplete: ... + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + def alarm_cancel(self, alarm_id: int = 0, /) -> None: + """ + Cancel a running alarm. + + The mimxrt port also exposes this function as ``RTC.cancel(alarm_id=0)``, but this is + scheduled to be removed in MicroPython 2.0. + """ + ... + def alarm_left(self, alarm_id: int = 0, /) -> int: + """ + Get the number of milliseconds left before the alarm expires. + """ + ... + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + +class SPI: + """ + SPI is a synchronous serial protocol that is driven by a controller. At the + physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices + can share the same bus. Each device should have a separate, 4th signal, + CS (Chip Select), to select a particular device on a bus with which + communication takes place. Management of a CS signal should happen in + user code (via machine.Pin class). + + Both hardware and software SPI implementations exist via the + :ref:`machine.SPI ` and `machine.SoftSPI` classes. Hardware SPI uses underlying + hardware support of the system to perform the reads/writes and is usually + efficient and fast but may have restrictions on which pins can be used. + Software SPI is implemented by bit-banging and can be used on any pin but + is not as efficient. These classes have the same methods available and + differ primarily in the way they are constructed. + + Example usage:: + + from machine import SPI, Pin + + spi = SPI(0, baudrate=400000) # Create SPI peripheral 0 at frequency of 400kHz. + # Depending on the use case, extra parameters may be required + # to select the bus characteristics and/or pins to use. + cs = Pin(4, mode=Pin.OUT, value=1) # Create chip-select on pin 4. + + try: + cs(0) # Select peripheral. + spi.write(b"12345678") # Write 8 bytes, and don't care about received data. + finally: + cs(1) # Deselect peripheral. + + try: + cs(0) # Select peripheral. + rxdata = spi.read(8, 0x42) # Read 8 bytes while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + rxdata = bytearray(8) + try: + cs(0) # Select peripheral. + spi.readinto(rxdata, 0x42) # Read 8 bytes inplace while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + txdata = b"12345678" + rxdata = bytearray(len(txdata)) + try: + cs(0) # Select peripheral. + spi.write_readinto(txdata, rxdata) # Simultaneously write and read bytes. + finally: + cs(1) # Deselect peripheral. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + CONTROLLER: Incomplete + def deinit(self) -> None: + """ + Turn off the SPI bus. + """ + ... + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + def write_readinto(self, write_buf: AnyReadableBuf, read_buf: AnyWritableBuf, /) -> int: + """ + Write the bytes from ``write_buf`` while reading into ``read_buf``. The + buffers can be the same or different, but both buffers must have the + same length. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def read(self, nbytes: int, write: int = 0x00, /) -> bytes: + """ + Read a number of bytes specified by ``nbytes`` while continuously writing + the single byte given by ``write``. + Returns a ``bytes`` object with the data that was read. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes contained in ``buf``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def readinto(self, buf: AnyWritableBuf, write: int = 0x00, /) -> int: + """ + Read into the buffer specified by ``buf`` while continuously writing the + single byte given by ``write``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes read. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/math.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/math.pyi new file mode 100644 index 000000000..606eb1389 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/math.pyi @@ -0,0 +1,269 @@ +""" +Mathematical functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/math.html + +CPython module: :mod:`python:math` https://docs.python.org/3/library/math.html . + +The ``math`` module provides some basic mathematical functions for +working with floating-point numbers. + +*Note:* On the pyboard, floating-point numbers have 32-bit precision. + +Availability: not available on WiPy. Floating point support required +for this module. + +--- +Module: 'math' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsFloat, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +inf: float = inf +nan: float = nan +pi: float = 3.1415928 +"""the ratio of a circle's circumference to its diameter""" +e: float = 2.7182818 +"""base of the natural logarithm""" +tau: float = 6.2831856 + +def ldexp(x: SupportsFloat, exp: int, /) -> float: + """ + Return ``x * (2**exp)``. + """ + ... + +def lgamma(x: SupportsFloat, /) -> float: + """ + Return the natural logarithm of the gamma function of ``x``. + """ + ... + +def trunc(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards 0. + """ + ... + +def isclose(*args, **kwargs) -> Incomplete: ... +def gamma(x: SupportsFloat, /) -> float: + """ + Return the gamma function of ``x``. + """ + ... + +def isnan(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is not-a-number + """ + ... + +def isfinite(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is finite. + """ + ... + +def isinf(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is infinite. + """ + ... + +def sqrt(x: SupportsFloat, /) -> float: + """ + Return the square root of ``x``. + """ + ... + +def sinh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic sine of ``x``. + """ + ... + +def log(x: SupportsFloat, /) -> float: + """ + With one argument, return the natural logarithm of *x*. + + With two arguments, return the logarithm of *x* to the given *base*. + """ + ... + +def tan(x: SupportsFloat, /) -> float: + """ + Return the tangent of ``x``. + """ + ... + +def tanh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic tangent of ``x``. + """ + ... + +def log2(x: SupportsFloat, /) -> float: + """ + Return the base-2 logarithm of ``x``. + """ + ... + +def log10(x: SupportsFloat, /) -> float: + """ + Return the base-10 logarithm of ``x``. + """ + ... + +def sin(x: SupportsFloat, /) -> float: + """ + Return the sine of ``x``. + """ + ... + +def modf(x: SupportsFloat, /) -> Tuple: + """ + Return a tuple of two floats, being the fractional and integral parts of + ``x``. Both return values have the same sign as ``x``. + """ + ... + +def radians(x: SupportsFloat, /) -> float: + """ + Return degrees ``x`` converted to radians. + """ + ... + +def atanh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic tangent of ``x``. + """ + ... + +def atan2(y: SupportsFloat, x: SupportsFloat, /) -> float: + """ + Return the principal value of the inverse tangent of ``y/x``. + """ + ... + +def atan(x: SupportsFloat, /) -> float: + """ + Return the inverse tangent of ``x``. + """ + ... + +def ceil(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards positive infinity. + """ + ... + +def copysign(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return ``x`` with the sign of ``y``. + """ + ... + +def frexp(x: SupportsFloat, /) -> tuple[float, 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 acos(x: SupportsFloat, /) -> float: + """ + Return the inverse cosine of ``x``. + """ + ... + +def pow(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Returns ``x`` to the power of ``y``. + """ + ... + +def asinh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic sine of ``x``. + """ + ... + +def acosh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic cosine of ``x``. + """ + ... + +def asin(x: SupportsFloat, /) -> float: + """ + Return the inverse sine of ``x``. + """ + ... + +def factorial(*args, **kwargs) -> Incomplete: ... +def fabs(x: SupportsFloat, /) -> float: + """ + Return the absolute value of ``x``. + """ + ... + +def expm1(x: SupportsFloat, /) -> float: + """ + Return ``exp(x) - 1``. + """ + ... + +def floor(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards negative infinity. + """ + ... + +def fmod(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return the remainder of ``x/y``. + """ + ... + +def cos(x: SupportsFloat, /) -> float: + """ + Return the cosine of ``x``. + """ + ... + +def degrees(x: SupportsFloat, /) -> float: + """ + Return radians ``x`` converted to degrees. + """ + ... + +def cosh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic cosine of ``x``. + """ + ... + +def exp(x: SupportsFloat, /) -> float: + """ + Return the exponential of ``x``. + """ + ... + +def erf(x: SupportsFloat, /) -> float: + """ + Return the error function of ``x``. + """ + ... + +def erfc(x: SupportsFloat, /) -> float: + """ + Return the complementary error function of ``x``. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/micropython.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/micropython.pyi new file mode 100644 index 000000000..527d48e8c --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/micropython.pyi @@ -0,0 +1,346 @@ +""" +Access and control MicroPython internals. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/micropython.html + +--- +Module: 'micropython' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Any, Callable, Optional, Tuple, overload +from typing_extensions import Awaitable, ParamSpec, TypeAlias, TypeVar + +_T = TypeVar("_T") +_F = TypeVar("_F", bound=Callable[..., Any]) +Const_T = TypeVar("Const_T", int, float, str, bytes, Tuple) +_Param = ParamSpec("_Param") +_Ret = TypeVar("_Ret") + +@overload +def opt_level() -> int: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def opt_level(level: int, /) -> None: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def mem_info() -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +@overload +def mem_info(verbose: Any, /) -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +def kbd_intr(chr: int) -> None: + """ + Set the character that will raise a `KeyboardInterrupt` exception. By + default this is set to 3 during script execution, corresponding to Ctrl-C. + Passing -1 to this function will disable capture of Ctrl-C, and passing 3 + will restore it. + + This function can be used to prevent the capturing of Ctrl-C on the + incoming stream of characters that is usually used for the REPL, in case + that stream is used for other purposes. + """ + ... + +@overload +def qstr_info() -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +@overload +def qstr_info(verbose: bool, /) -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +def schedule(func: Callable[[_T], None], arg: _T, /) -> None: + """ + Schedule the function *func* to be executed "very soon". The function + is passed the value *arg* as its single argument. "Very soon" means that + the MicroPython runtime will do its best to execute the function at the + earliest possible time, given that it is also trying to be efficient, and + that the following conditions hold: + + - A scheduled function will never preempt another scheduled function. + - Scheduled functions are always executed "between opcodes" which means + that all fundamental Python operations (such as appending to a list) + are guaranteed to be atomic. + - A given port may define "critical regions" within which scheduled + functions will never be executed. Functions may be scheduled within + a critical region but they will not be executed until that region + is exited. An example of a critical region is a preempting interrupt + handler (an IRQ). + + A use for this function is to schedule a callback from a preempting IRQ. + Such an IRQ puts restrictions on the code that runs in the IRQ (for example + the heap may be locked) and scheduling a function to call later will lift + those restrictions. + + On multi-threaded ports, the scheduled function's behaviour depends on + whether the Global Interpreter Lock (GIL) is enabled for the specific port: + + - If GIL is enabled, the function can preempt any thread and run in its + context. + - If GIL is disabled, the function will only preempt the main thread and run + in its context. + + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite queue to hold the scheduled functions and `schedule()` + will raise a `RuntimeError` if the queue is full. + """ + ... + +def stack_use() -> int: + """ + Return an integer representing the current amount of stack that is being + used. The absolute value of this is not particularly useful, rather it + should be used to compute differences in stack usage at different points. + """ + ... + +def heap_unlock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def const(expr: Const_T, /) -> Const_T: + """ + Used to declare that the expression is a constant so that the compiler can + optimise it. The use of this function should be as follows:: + + from micropython import const + + CONST_X = const(123) + CONST_Y = const(2 * CONST_X + 1) + + Constants declared this way are still accessible as global variables from + outside the module they are declared in. On the other hand, if a constant + begins with an underscore then it is hidden, it is not available as a global + variable, and does not take up any memory during execution. + + This `const` function is recognised directly by the MicroPython parser and is + provided as part of the :mod:`micropython` module mainly so that scripts can be + written which run under both CPython and MicroPython, by following the above + pattern. + """ + ... + +def heap_lock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def alloc_emergency_exception_buf(size: int, /) -> None: + """ + Allocate *size* bytes of RAM for the emergency exception buffer (a good + size is around 100 bytes). The buffer is used to create exceptions in cases + when normal RAM allocation would fail (eg within an interrupt handler) and + therefore give useful traceback information in these situations. + + A good way to use this function is to put it at the start of your main script + (eg ``boot.py`` or ``main.py``) and then the emergency exception buffer will be active + for all the code following it. + """ + ... + +class RingIO: + def readinto(self, buf, nbytes: Optional[Any] = None) -> int: + """ + Read available bytes into the provided ``buf``. If ``nbytes`` is + specified then read at most that many bytes. Otherwise, read at + most ``len(buf)`` bytes. + + Return value: Integer count of the number of bytes read into ``buf``. + """ + ... + def write(self, buf) -> int: + """ + Non-blocking write of bytes from ``buf`` into the ringbuffer, limited + by the available space in the ringbuffer. + + Return value: Integer count of bytes written. + """ + ... + def readline(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read a line, ending in a newline character or return if one exists in + the buffer, else return available bytes in buffer. If ``nbytes`` is + specified then read at most that many bytes. + + Return value: a bytes object containing the line read. + """ + ... + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read. + """ + ... + def read(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read available characters. This is a non-blocking function. If ``nbytes`` + is specified then read at most that many bytes, otherwise read as much + data as possible. + + Return value: a bytes object containing the bytes read. Will be + zero-length bytes object if no data is available. + """ + ... + def close(self) -> Incomplete: + """ + No-op provided as part of standard `stream` interface. Has no effect + on data in the ringbuffer. + """ + ... + def __init__(self, size) -> None: ... + +# decorators +@mp_available() # force merge +def viper(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + The Viper code emitter is not fully compliant. It supports special Viper native data types in pursuit of performance. + Integer processing is non-compliant because it uses machine words: arithmetic on 32 bit hardware is performed modulo 2**32. + Like the Native emitter Viper produces machine instructions but further optimisations are performed, substantially increasing + performance especially for integer arithmetic and bit manipulations. + See: https://docs.micropython.org/en/latest/reference/speed_python.html?highlight=viper#the-native-code-emitter + """ + ... + +@mp_available() # force merge +def native(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This causes the MicroPython compiler to emit native CPU opcodes rather than bytecode. + It covers the bulk of the MicroPython functionality, so most functions will require no adaptation. + See: https://docs.micropython.org/en/latest/reference/speed_python.html#the-native-code-emitter + """ + ... + +@mp_available(macro="MICROPY_EMIT_INLINE_THUMB") # force merge +def asm_thumb(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code. + The assembler code is written is a subset of the ARM Thumb-2 instruction set, and is executed on the target CPU. + + Availability: Only on specific boards where MICROPY_EMIT_INLINE_THUMB is defined. + See: https://docs.micropython.org/en/latest/reference/asm_thumb2_index.html + """ + ... + +@mp_available(port="esp8266") # force merge +def asm_xtensa(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code for the esp8266. + The assembler code is written in the Xtensa instruction set, and is executed on the target CPU. + + Availability: Only on eps8266 boards. + """ + ... + # See : + # - https://github.com/orgs/micropython/discussions/12965 + # - https://github.com/micropython/micropython/pull/16731 diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/mimxrt.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/mimxrt.pyi new file mode 100644 index 000000000..27ed8e301 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/mimxrt.pyi @@ -0,0 +1,14 @@ +""" +Module: 'mimxrt' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class Flash: + def readblocks(self, *args, **kwargs) -> Incomplete: ... + def writeblocks(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/network.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/network.pyi new file mode 100644 index 000000000..e6651185a --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/network.pyi @@ -0,0 +1,386 @@ +""" +Network configuration. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/network.html + +This module provides network drivers and routing configuration. To use this +module, a MicroPython variant/build with network capabilities must be installed. +Network drivers for specific hardware are available within this module and are +used to configure hardware network interface(s). Network services provided +by configured interfaces are then available for use via the :mod:`socket` +module. + +For example:: + + # connect/ show IP config a specific network interface + # see below for examples of specific drivers + import network + import time + nic = network.Driver(...) + if not nic.isconnected(): + nic.connect() + print("Waiting for connection...") + while not nic.isconnected(): + time.sleep(1) + print(nic.ipconfig("addr4")) + + # now use socket as usual + import socket + addr = socket.getaddrinfo('micropython.org', 80)[0][-1] + s = socket.socket() + s.connect(addr) + s.send(b'GET / HTTP/1.1 +Host: micropython.org + +') + data = s.recv(1000) + s.close() + +--- +Module: 'network' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Protocol, Callable, overload, Any, List, Optional, Tuple, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar +from machine import Pin, SPI +from abc import abstractmethod + +STA_IF: Final[int] = 0 +AP_IF: Final[int] = 1 + +def hostname(name: Optional[Any] = None) -> Incomplete: + """ + Get or set the hostname that will identify this device on the network. It will + be used by all interfaces. + + This hostname is used for: + * Sending to the DHCP server in the client request. (If using DHCP) + * Broadcasting via mDNS. (If enabled) + + If the *name* parameter is provided, the hostname will be set to this value. + If the function is called without parameters, it returns the current + hostname. + + A change in hostname is typically only applied during connection. For DHCP + this is because the hostname is part of the DHCP client request, and the + implementation of mDNS in most ports only initialises the hostname once + during connection. For this reason, you must set the hostname before + activating/connecting your network interfaces. + + The length of the hostname is limited to 32 characters. + :term:`MicroPython ports ` may choose to set a lower + limit for memory reasons. If the given name does not fit, a `ValueError` + is raised. + + The default hostname is typically the name of the board. + """ + ... + +def route(*args, **kwargs) -> Incomplete: ... +def country(code: Optional[Any] = None) -> Incomplete: + """ + Get or set the two-letter ISO 3166-1 Alpha-2 country code to be used for + radio compliance. + + If the *code* parameter is provided, the country will be set to this value. + If the function is called without parameters, it returns the current + country. + + The default code ``"XX"`` represents the "worldwide" region. + """ + ... + +class WLANWiPy: + @overload + def __init__(self, id: int = 0, /): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int, + ssid: str, + auth: tuple[str, str], + channel: int, + antenna: int, + ): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def mode(self) -> int: + """ + Get or set the WLAN mode. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the WLAN mode. + """ + + @overload + def ssid(self) -> str: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def ssid(self, ssid: str, /) -> None: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def auth(self) -> int: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def auth(self, auth: int, /) -> None: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def channel(self) -> int: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def channel(self, channel: int, /) -> None: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def antenna(self) -> int: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def antenna(self, antenna: int, /) -> None: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def mac(self) -> bytes: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + + @overload + def mac(self, mac: bytes, /) -> None: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + +class AbstractNIC: + @overload + @abstractmethod + def active(self, /) -> bool: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def active(self, is_active: bool | int, /) -> None: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def connect(self, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def connect(self, service_id: Any, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def status(self) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def status(self, param: str, /) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def ifconfig(self) -> tuple[str, str, str, str]: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def ifconfig(self, ip_mask_gateway_dns: tuple[str, str, str, str], /) -> None: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def config(self, param: str, /) -> Any: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ + + @overload + @abstractmethod + def config(self, **kwargs: Any) -> None: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ + +class LAN: + @overload + def active(self, /) -> bool: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ + + @overload + def active(self, is_active: bool | int, /) -> None: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/onewire.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/onewire.pyi new file mode 100644 index 000000000..0f342b252 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/onewire.pyi @@ -0,0 +1,28 @@ +""" +Module: 'onewire' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SKIP_ROM: Final[int] = 204 + SEARCH_ROM: Final[int] = 240 + MATCH_ROM: Final[int] = 85 + def select_rom(self, *args, **kwargs) -> Incomplete: ... + def writebit(self, *args, **kwargs) -> Incomplete: ... + def writebyte(self, *args, **kwargs) -> Incomplete: ... + def _search_rom(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def crc8(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def reset(self, *args, **kwargs) -> Incomplete: ... + def readbit(self, *args, **kwargs) -> Incomplete: ... + def readbyte(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/platform.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/platform.pyi new file mode 100644 index 000000000..cc7c88d22 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/platform.pyi @@ -0,0 +1,51 @@ +""" +Access to underlying platform’s identifying data. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/platform.html + +CPython module: :mod:`python:platform` https://docs.python.org/3/library/platform.html . + +This module tries to retrieve as much platform-identifying data as possible. It +makes this information available via function APIs. + +--- +Module: 'platform' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def platform() -> str: + """ + Returns a string identifying the underlying platform. This string is composed + of several substrings in the following order, delimited by dashes (``-``): + + - the name of the platform system (e.g. Unix, Windows or MicroPython) + - the MicroPython version + - the architecture of the platform + - the version of the underlying platform + - the concatenation of the name of the libc that MicroPython is linked to + and its corresponding version. + + For example, this could be + ``"MicroPython-1.20.0-xtensa-IDFv4.2.4-with-newlib3.0.0"``. + """ + ... + +def python_compiler() -> str: + """ + Returns a string identifying the compiler used for compiling MicroPython. + """ + ... + +def libc_ver() -> Tuple: + """ + Returns a tuple of strings *(lib, version)*, where *lib* is the name of the + libc that MicroPython is linked to, and *version* the corresponding version + of this libc. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/pyproject.toml b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/pyproject.toml new file mode 100644 index 000000000..998c0095d --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/pyproject.toml @@ -0,0 +1,102 @@ +[project] +name = "micropython-mimxrt-mimxrt1010_evk-stubs" +description = "MicroPython stubs" +version = "1.26.1.post1" +readme = "README.md" +license = "MIT" +authors = [ + { name = "Jos Verlinde", email = "josverl@users.noreply.github.com" }, +] +classifiers = [ + "Typing :: Stubs Only", + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Implementation :: MicroPython", + "Operating System :: OS Independent", + "Topic :: Text Editors :: Integrated Development Environments (IDE)", + "Topic :: Software Development :: Documentation", + "Topic :: Software Development :: Embedded Systems", + "Topic :: Software Development :: Testing", + "Natural Language :: English", +] +dependencies = [ + "micropython-stdlib-stubs ~=1.26.0", +] + +[project.urls] +homepage = "https://github.com/josverl/micropython-stubs#micropython-stubs" +documentation = "https://micropython-stubs.readthedocs.io/" +repository = "https://github.com/josverl/micropython-stubs" + +[tool.poetry] +exclude = [ + "*.ps1", + "*.py", + "**/__pycache__", + "**/dist", +] +include = [ + "**/*.py", + "**/*.pyi", +] +packages = [ + { include = "__builtins__.pyi" }, + { include = "_onewire.pyi" }, + { include = "binascii.pyi" }, + { include = "cmath.pyi" }, + { include = "deflate.pyi" }, + { include = "dht.pyi" }, + { include = "ds18x20.pyi" }, + { include = "errno.pyi" }, + { include = "framebuf.pyi" }, + { include = "gc.pyi" }, + { include = "hashlib.pyi" }, + { include = "heapq.pyi" }, + { include = "machine.pyi" }, + { include = "math.pyi" }, + { include = "micropython.pyi" }, + { include = "mimxrt.pyi" }, + { include = "network.pyi" }, + { include = "onewire.pyi" }, + { include = "platform.pyi" }, + { include = "random.pyi" }, + { include = "select.pyi" }, + { include = "socket.pyi" }, + { include = "time.pyi" }, + { include = "uarray.pyi" }, + { include = "uasyncio.pyi" }, + { include = "ubinascii.pyi" }, + { include = "ubluetooth.pyi" }, + { include = "ucollections.pyi" }, + { include = "ucryptolib.pyi" }, + { include = "uctypes.pyi" }, + { include = "uerrno.pyi" }, + { include = "uhashlib.pyi" }, + { include = "uheapq.pyi" }, + { include = "uio.pyi" }, + { include = "ujson.pyi" }, + { include = "umachine.pyi" }, + { include = "uos.pyi" }, + { include = "uplatform.pyi" }, + { include = "urandom.pyi" }, + { include = "ure.pyi" }, + { include = "usb/device/cdc.pyi" }, + { include = "usb/device.pyi" }, + { include = "uselect.pyi" }, + { include = "usocket.pyi" }, + { include = "ussl.pyi" }, + { include = "ustruct.pyi" }, + { include = "usys.pyi" }, + { include = "utime.pyi" }, + { include = "uwebsocket.pyi" }, + { include = "uzlib.pyi" }, + { include = "vfs.pyi" }, +] + +[build-system] +requires = [ + "poetry-core>=1.0.0", +] +build-backend = "poetry.core.masonry.api" diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/random.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/random.pyi new file mode 100644 index 000000000..bb5167074 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/random.pyi @@ -0,0 +1,115 @@ +""" +Random numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/random.html + +This module implements a pseudo-random number generator (PRNG). + +CPython module: :mod:`python:random` https://docs.python.org/3/library/random.html . . + +.. note:: + + The following notation is used for intervals: + + - () are open interval brackets and do not include their endpoints. + For example, (0, 1) means greater than 0 and less than 1. + In set notation: (0, 1) = {x | 0 < x < 1}. + + - [] are closed interval brackets which include all their limit points. + For example, [0, 1] means greater than or equal to 0 and less than + or equal to 1. + In set notation: [0, 1] = {x | 0 <= x <= 1}. + +.. note:: + + The :func:`randrange`, :func:`randint` and :func:`choice` functions are only + available if the ``MICROPY_PY_RANDOM_EXTRA_FUNCS`` configuration option is + enabled. + +--- +Module: 'random' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import Subscriptable +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +@overload +def randrange(stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, step: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +def random() -> int: + """ + Return a random floating point number in the range [0.0, 1.0). + """ + ... + +def seed(n: int | None = None, /) -> None: + """ + Initialise the random number generator module with the seed *n* which should + be an integer. When no argument (or ``None``) is passed in it will (if + supported by the port) initialise the PRNG with a true random number + (usually a hardware generated random number). + + The ``None`` case only works if ``MICROPY_PY_RANDOM_SEED_INIT_FUNC`` is + enabled by the port, otherwise it raises ``ValueError``. + """ + ... + +def uniform(a: float, b: float) -> int: + """ + Return a random floating point number N such that *a* <= N <= *b* for *a* <= *b*, + and *b* <= N <= *a* for *b* < *a*. + """ + ... + +def choice(sequence: Subscriptable, /) -> None: + """ + Chooses and returns one item at random from *sequence* (tuple, list or + any object that supports the subscript operation). + """ + ... + +def randint(a: int, b: int, /) -> int: + """ + Return a random integer in the range [*a*, *b*]. + """ + ... + +def getrandbits(n: int, /) -> int: + """ + Return an integer with *n* random bits (0 <= n <= 32). + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/select.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/select.pyi new file mode 100644 index 000000000..b2a5aa0e8 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/select.pyi @@ -0,0 +1,118 @@ +""" +Wait for events on a set of streams. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/select.html + +CPython module: :mod:`python:select` https://docs.python.org/3/library/select.html . + +This module provides functions to efficiently wait for events on multiple +`streams ` (select streams which are ready for operations). + +--- +Module: 'select' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Iterable, Iterator, List, Optional, Tuple, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +POLLOUT: Final[int] = 4 +POLLIN: Final[int] = 1 +POLLHUP: Final[int] = 16 +POLLERR: Final[int] = 8 + +def select( + rlist: Iterable[Any], + wlist: Iterable[Any], + xlist: Iterable[Any], + timeout: int = -1, + /, +) -> None: + """ + Wait for activity on a set of objects. + + This function is provided by some MicroPython ports for compatibility + and is not efficient. Usage of :class:`Poll` is recommended instead. + """ + ... + +class poll: + """ + Create an instance of the Poll class. + """ + def __init__(self) -> None: ... + def register(self, obj, eventmask: Optional[Any] = None) -> None: + """ + Register `stream` *obj* for polling. *eventmask* is logical OR of: + + * ``select.POLLIN`` - data available for reading + * ``select.POLLOUT`` - more data can be written + + Note that flags like ``select.POLLHUP`` and ``select.POLLERR`` are + *not* valid as input eventmask (these are unsolicited events which + will be returned from `poll()` regardless of whether they are asked + for). This semantics is per POSIX. + + *eventmask* defaults to ``select.POLLIN | select.POLLOUT``. + + It is OK to call this function multiple times for the same *obj*. + Successive calls will update *obj*'s eventmask to the value of + *eventmask* (i.e. will behave as `modify()`). + """ + ... + def unregister(self, obj) -> Incomplete: + """ + Unregister *obj* from polling. + """ + ... + def modify(self, obj, eventmask) -> None: + """ + Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError` + is raised with error of ENOENT. + """ + ... + def poll(self, timeout=-1, /) -> List: + """ + Wait for at least one of the registered objects to become ready or have an + exceptional condition, with optional timeout in milliseconds (if *timeout* + arg is not specified or -1, there is no timeout). + + Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in + tuple, depending on a platform and version, so don't assume that its size is 2. + The ``event`` element specifies which events happened with a stream and + is a combination of ``select.POLL*`` constants described above. Note that + flags ``select.POLLHUP`` and ``select.POLLERR`` can be returned at any time + (even if were not asked for), and must be acted on accordingly (the + corresponding stream unregistered from poll and likely closed), because + otherwise all further invocations of `poll()` may return immediately with + these flags set for this stream again. + + In case of timeout, an empty list is returned. + + Admonition:Difference to CPython + :class: attention + + Tuples returned may contain more than 2 elements as described above. + """ + ... + def ipoll(self, timeout=-1, flags=0, /) -> Iterator[Tuple]: + """ + Like :meth:`poll.poll`, but instead returns an iterator which yields a + `callee-owned tuple`. This function provides an efficient, allocation-free + way to poll on streams. + + If *flags* is 1, one-shot behaviour for events is employed: streams for + which events happened will have their event masks automatically reset + (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream + won't be processed until new mask is set with `poll.modify()`. This + behaviour is useful for asynchronous I/O schedulers. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/socket.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/socket.pyi new file mode 100644 index 000000000..c639ed769 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/socket.pyi @@ -0,0 +1,419 @@ +""" +Socket module. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/socket.html + +CPython module: :mod:`python:socket` https://docs.python.org/3/library/socket.html . + +This module provides access to the BSD socket interface. + +Admonition:Difference to CPython + :class: attention + + For efficiency and consistency, socket objects in MicroPython implement a `stream` + (file-like) interface directly. In CPython, you need to convert a socket to + a file-like object using `makefile()` method. This method is still supported + by MicroPython (but is a no-op), so where compatibility with CPython matters, + be sure to use it. + +Socket address format(s) +------------------------ + +The native socket address format of the ``socket`` module is an opaque data type +returned by `getaddrinfo` function, which must be used to resolve textual address +(including numeric addresses):: + + sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1] + # You must use getaddrinfo() even for numeric addresses + sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1] + # Now you can use that address + sock.connect(sockaddr) + +Using `getaddrinfo` is the most efficient (both in terms of memory and processing +power) and portable way to work with addresses. + +However, ``socket`` module (note the difference with native MicroPython +``socket`` module described here) provides CPython-compatible way to specify +addresses using tuples, as described below. Note that depending on a +:term:`MicroPython port`, ``socket`` module can be builtin or need to be +installed from `micropython-lib` (as in the case of :term:`MicroPython Unix port`), +and some ports still accept only numeric addresses in the tuple format, +and require to use `getaddrinfo` function to resolve domain names. + +Summing up: + +* Always use `getaddrinfo` when writing portable applications. +* Tuple addresses described below can be used as a shortcut for + quick hacks and interactive use, if your port supports them. + +Tuple address format for ``socket`` module: + +* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with + dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and + integer port number in the range 1-65535. Note the domain names are not + accepted as *ipv4_address*, they should be resolved first using + `socket.getaddrinfo()`. +* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address* + is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``, + and *port* is an integer port number in the range 1-65535. *flowinfo* + must be 0. *scopeid* is the interface scope identifier for link-local + addresses. Note the domain names are not accepted as *ipv6_address*, + they should be resolved first using `socket.getaddrinfo()`. Availability + of IPv6 support depends on a :term:`MicroPython port`. + +--- +Module: 'socket' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Literal, Tuple, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +SO_KEEPALIVE: Final[int] = 8 +SO_BROADCAST: Final[int] = 32 +SOL_SOCKET: Final[int] = 4095 +SO_RCVTIMEO: Final[int] = 4102 +SO_REUSEADDR: Final[int] = 4 +SO_SNDTIMEO: Final[int] = 4101 +AF_INET6: Final[int] = 10 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +AF_INET: Final[int] = 2 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +SOCK_STREAM: Final[int] = 1 +"""Socket types.""" +SOCK_DGRAM: Final[int] = 2 +"""Socket types.""" +SOCK_RAW: Final[int] = 3 +IPPROTO_UDP: Incomplete +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IPPROTO_TCP: Incomplete +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IPPROTO_SEC: Incomplete +"""Special protocol value to create SSL-compatible socket.""" +_Address: TypeAlias = tuple[str, int] | tuple[str, int, int, int] | str +Socket: TypeAlias = socket + +def getaddrinfo( + host: str, + port: int, + af: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, + /, +) -> list[tuple[int, int, int, str, tuple[str, int] | tuple[str, int, int, int]]]: + """ + Translate the host/port argument into a sequence of 5-tuples that contain all the + necessary arguments for creating a socket connected to that service. Arguments + *af*, *type*, and *proto* (which have the same meaning as for the `socket()` function) + can be used to filter which kind of addresses are returned. If a parameter is not + specified or zero, all combinations of addresses can be returned (requiring + filtering on the user side). + + The resulting list of 5-tuples has the following structure:: + + (family, type, proto, canonname, sockaddr) + + The following example shows how to connect to a given url:: + + s = socket.socket() + # This assumes that if "type" is not specified, an address for + # SOCK_STREAM will be returned, which may be not true + s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1]) + + Recommended use of filtering params:: + + s = socket.socket() + # Guaranteed to return an address which can be connect'ed to for + # stream operation. + s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1]) + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.gaierror`` exception (`OSError` subclass) in case + of error in this function. MicroPython doesn't have ``socket.gaierror`` + and raises OSError directly. Note that error numbers of `getaddrinfo()` + form a separate namespace and may not match error numbers from + the :mod:`errno` module. To distinguish `getaddrinfo()` errors, they are + represented by negative numbers, whereas standard system errors are + positive numbers (error numbers are accessible using ``e.args[0]`` property + from an exception object). The use of negative values is a provisional + detail which may change in the future. + """ + ... + +class socket: + """ + A unix like socket, for more information see module ``socket``'s description. + + The name, `Socket`, used for typing is not the same as the runtime name, `socket` (note lowercase `s`). + The reason for this difference is that the runtime uses `socket` as both a class name and as a method name and + this is not possible within code written entirely in Python and therefore not possible within typing code. + """ + def recvfrom(self, bufsize: int, /) -> Tuple: + """ + Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a + bytes object representing the data received and *address* is the address of the socket sending + the data. + + See the `recv` function for an explanation of the optional *flags* argument. + """ + ... + def recv(self, bufsize: int, /) -> bytes: + """ + Receive data from the socket. The return value is a bytes object representing the data + received. The maximum amount of data to be received at once is specified by bufsize. + + Most ports support the optional *flags* argument. Available *flags* are defined as constants + in the socket module and have the same meaning as in CPython. ``MSG_PEEK`` and ``MSG_DONTWAIT`` + are supported on all ports which accept the *flags* argument. + """ + ... + + @overload + def makefile(self, mode: Literal["rb", "wb", "rwb"] = "rb", buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + + @overload + def makefile(self, mode: str, buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + def listen(self, backlog: int = ..., /) -> None: + """ + Enable a server to accept connections. If *backlog* is specified, it must be at least 0 + (if it's lower, it will be set to 0); and specifies the number of unaccepted connections + that the system will allow before refusing new connections. If not specified, a default + reasonable value is chosen. + """ + ... + def settimeout(self, value: float | None, /) -> None: + """ + **Note**: Not every port supports this method, see below. + + Set a timeout on blocking socket operations. The value argument can be a nonnegative floating + point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations + will raise an `OSError` exception if the timeout period value has elapsed before the operation has + completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket + is put in blocking mode. + + Not every :term:`MicroPython port` supports this method. A more portable and + generic solution is to use `select.poll` object. This allows to wait on + multiple objects at the same time (and not just on sockets, but on generic + `stream` objects which support polling). Example:: + + # Instead of: + s.settimeout(1.0) # time in seconds + s.read(10) # may timeout + + # Use: + poller = select.poll() + poller.register(s, select.POLLIN) + res = poller.poll(1000) # time in milliseconds + if not res: + # s is still not ready for input, i.e. operation timed out + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.timeout`` exception in case of timeout, + which is an `OSError` subclass. MicroPython raises an OSError directly + instead. If you use ``except OSError:`` to catch the exception, + your code will work both in MicroPython and CPython. + """ + ... + def sendall(self, bytes: AnyReadableBuf, /) -> int: + """ + Send all data to the socket. The socket must be connected to a remote socket. + Unlike `send()`, this method will try to send all of data, by sending data + chunk by chunk consecutively. + + The behaviour of this method on non-blocking sockets is undefined. Due to this, + on MicroPython, it's recommended to use `write()` method instead, which + has the same "no short writes" policy for blocking sockets, and will return + number of bytes sent on non-blocking sockets. + """ + ... + def setsockopt(self, level: int, optname: int, value: AnyReadableBuf | int, /) -> None: + """ + Set the value of the given socket option. The needed symbolic constants are defined in the + socket module (SO_* etc.). The *value* can be an integer or a bytes-like object representing + a buffer. + """ + ... + def setblocking(self, value: bool, /) -> None: + """ + Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking, + else to blocking mode. + + This method is a shorthand for certain `settimeout()` calls: + + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)`` + """ + ... + def sendto(self, bytes: AnyReadableBuf, address: _Address, /) -> None: + """ + Send data to the socket. The socket should not be connected to a remote socket, since the + destination socket is specified by *address*. + """ + ... + def readline(self) -> bytes: + """ + Read a line, ending in a newline character. + + Return value: the line read. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def read(self) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + + @overload + def read(self, size: int, /) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + def close(self) -> None: + """ + Mark the socket closed and release all resources. Once that happens, all future operations + on the socket object will fail. The remote end will receive EOF indication if + supported by protocol. + + Sockets are automatically closed when they are garbage-collected, but it is recommended + to `close()` them explicitly as soon you finished working with them. + """ + ... + def connect(self, address: _Address | bytes, /) -> None: + """ + Connect to a remote socket at *address*. + """ + ... + def send(self, bytes: AnyReadableBuf, /) -> int: + """ + Send data to the socket. The socket must be connected to a remote socket. + Returns number of bytes sent, which may be smaller than the length of data + ("short write"). + """ + ... + def bind(self, address: _Address | bytes, /) -> None: + """ + Bind the socket to *address*. The socket must not already be bound. + """ + ... + def accept(self) -> Tuple: + """ + Accept a connection. The socket must be bound to an address and listening for connections. + The return value is a pair (conn, address) where conn is a new socket object usable to send + and receive data on the connection, and address is the address bound to the socket on the + other end of the connection. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the buffer of bytes to the socket. This function will try to + write all data to a socket (no "short writes"). This may be not possible + with a non-blocking socket though, and returned value will be less than + the length of *buf*. + + Return value: number of bytes written. + """ + ... + def __init__( + self, + af: int = AF_INET, + type: int = SOCK_STREAM, + proto: int = IPPROTO_TCP, + /, + ) -> None: + """ + Create a new socket using the given address family, socket type and + protocol number. Note that specifying *proto* in most cases is not + required (and not recommended, as some MicroPython ports may omit + ``IPPROTO_*`` constants). Instead, *type* argument will select needed + protocol automatically:: + + # Create STREAM TCP socket + socket(AF_INET, SOCK_STREAM) + # Create DGRAM UDP socket + socket(AF_INET, SOCK_DGRAM) + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/time.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/time.pyi new file mode 100644 index 000000000..f2bbac553 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/time.pyi @@ -0,0 +1,306 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. + +--- +Module: 'time' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def ticks_diff(ticks1: _Ticks, ticks2: _Ticks, /) -> int: + """ + Measure ticks difference between values returned from `ticks_ms()`, `ticks_us()`, + or `ticks_cpu()` functions, as a signed value which may wrap around. + + The argument order is the same as for subtraction + operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. + However, values returned by `ticks_ms()`, etc. functions may wrap around, so + directly using subtraction on them will produce incorrect result. That is why + `ticks_diff()` is needed, it implements modular (or more specifically, ring) + arithmetic to produce correct result even for wrap-around values (as long as they not + too distant in between, see below). The function returns **signed** value in the range + [*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for + two's-complement signed binary integers). If the result is negative, it means that + *ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that + *ticks1* occurred after *ticks2*. This holds **only** if *ticks1* and *ticks2* + are apart from each other for no more than *TICKS_PERIOD/2-1* ticks. If that does + not hold, incorrect result will be returned. Specifically, if two tick values are + apart for *TICKS_PERIOD/2-1* ticks, that value will be returned by the function. + However, if *TICKS_PERIOD/2* of real-time ticks has passed between them, the + function will return *-TICKS_PERIOD/2* instead, i.e. result value will wrap around + to the negative range of possible values. + + Informal rationale of the constraints above: Suppose you are locked in a room with no + means to monitor passing of time except a standard 12-notch clock. Then if you look at + dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a + long sleep), then once you finally look again, it may seem to you that only 1 hour + has passed. To avoid this mistake, just look at the clock regularly. Your application + should do the same. "Too long sleep" metaphor also maps directly to application + behaviour: don't let your application run any single task for too long. Run tasks + in steps, and do time-keeping in between. + + `ticks_diff()` is designed to accommodate various usage patterns, among them: + + * Polling with timeout. In this case, the order of events is known, and you will deal + only with positive results of `ticks_diff()`:: + + # Wait for GPIO pin to be asserted, but at most 500us + start = time.ticks_us() + while pin.value() == 0: + if time.ticks_diff(time.ticks_us(), start) > 500: + raise TimeoutError + + * Scheduling events. In this case, `ticks_diff()` result may be negative + if an event is overdue:: + + # This code snippet is not optimized + now = time.ticks_ms() + scheduled_time = task.scheduled_time() + if ticks_diff(scheduled_time, now) > 0: + print("Too early, let's nap") + sleep_ms(ticks_diff(scheduled_time, now)) + task.run() + elif ticks_diff(scheduled_time, now) == 0: + print("Right at time!") + task.run() + elif ticks_diff(scheduled_time, now) < 0: + print("Oops, running late, tell task to run faster!") + task.run(run_faster=true) + + Note: Do not pass `time()` values to `ticks_diff()`, you should use + normal mathematical operations on them. But note that `time()` may (and will) + also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem . + """ + ... + +def ticks_add(ticks: _Ticks, delta: int, /) -> _Ticks: + """ + Offset ticks value by a given number, which can be either positive or negative. + Given a *ticks* value, this function allows to calculate ticks value *delta* + ticks before or after it, following modular-arithmetic definition of tick values + (see `ticks_ms()` above). *ticks* parameter must be a direct result of call + to `ticks_ms()`, `ticks_us()`, or `ticks_cpu()` functions (or from previous + call to `ticks_add()`). However, *delta* can be an arbitrary integer number + or numeric expression. `ticks_add()` is useful for calculating deadlines for + events/tasks. (Note: you must use `ticks_diff()` function to work with + deadlines.) + + Examples:: + + # Find out what ticks value there was 100ms ago + print(ticks_add(time.ticks_ms(), -100)) + + # Calculate deadline for operation and test for it + deadline = ticks_add(time.ticks_ms(), 200) + while ticks_diff(deadline, time.ticks_ms()) > 0: + do_a_little_of_something() + + # Find out TICKS_MAX used by this port + print(ticks_add(0, -1)) + """ + ... + +def ticks_cpu() -> _TicksCPU: + """ + Similar to `ticks_ms()` and `ticks_us()`, but with the highest possible resolution + in the system. This is usually CPU clocks, and that's why the function is named that + way. But it doesn't have to be a CPU clock, some other timing source available in a + system (e.g. high-resolution timer) can be used instead. The exact timing unit + (resolution) of this function is not specified on ``time`` module level, but + documentation for a specific port may provide more specific information. This + function is intended for very fine benchmarking or very tight real-time loops. + Avoid using it in portable code. + + Availability: Not every port implements this function. + """ + ... + +def time() -> int: + """ + Returns the number of seconds, as an integer, since the Epoch, assuming that + underlying RTC is set and maintained as described above. If an RTC is not set, this + function returns number of seconds since a port-specific reference point in time (for + embedded boards without a battery-backed RTC, usually since power up or reset). If you + want to develop portable MicroPython application, you should not rely on this function + to provide higher than second precision. If you need higher precision, absolute + timestamps, use `time_ns()`. If relative times are acceptable then use the + `ticks_ms()` and `ticks_us()` functions. If you need calendar time, `gmtime()` or + `localtime()` without an argument is a better choice. + + Admonition:Difference to CPython + :class: attention + + In CPython, this function returns number of + seconds since Unix epoch, 1970-01-01 00:00 UTC, as a floating-point, + usually having microsecond precision. With MicroPython, only Unix port + uses the same Epoch, and if floating-point precision allows, + returns sub-second precision. Embedded hardware usually doesn't have + floating-point precision to represent both long time ranges and subsecond + precision, so they use integer value with second precision. Some embedded + hardware also lacks battery-powered RTC, so returns number of seconds + since last power-up or from other relative, hardware-specific point + (e.g. reset). + """ + ... + +def ticks_ms() -> int: + """ + Returns an increasing millisecond counter with an arbitrary reference point, that + wraps around after some value. + + The wrap-around value is not explicitly exposed, but we will + refer to it as *TICKS_MAX* to simplify discussion. Period of the values is + *TICKS_PERIOD = TICKS_MAX + 1*. *TICKS_PERIOD* is guaranteed to be a power of + two, but otherwise may differ from port to port. The same period value is used + for all of `ticks_ms()`, `ticks_us()`, `ticks_cpu()` functions (for + simplicity). Thus, these functions will return a value in range [*0* .. + *TICKS_MAX*], inclusive, total *TICKS_PERIOD* values. Note that only + non-negative values are used. For the most part, you should treat values returned + by these functions as opaque. The only operations available for them are + `ticks_diff()` and `ticks_add()` functions described below. + + Note: Performing standard mathematical operations (+, -) or relational + operators (<, <=, >, >=) directly on these value will lead to invalid + result. Performing mathematical operations and then passing their results + as arguments to `ticks_diff()` or `ticks_add()` will also lead to + invalid results from the latter functions. + """ + ... + +def ticks_us() -> _TicksUs: + """ + Just like `ticks_ms()` above, but in microseconds. + """ + ... + +def time_ns() -> int: + """ + Similar to `time()` but returns nanoseconds since the Epoch, as an integer (usually + a big integer, so will allocate on the heap). + """ + ... + +def localtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_us(us: int, /) -> None: + """ + Delay for given number of microseconds, should be positive or 0. + + This function attempts to provide an accurate delay of at least *us* + microseconds, but it may take longer if the system has other higher priority + processing to perform. + """ + ... + +def gmtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_ms(ms: int, /) -> None: + """ + Delay for given number of milliseconds, should be positive or 0. + + This function will delay for at least the given number of milliseconds, but + may take longer than that if other processing must take place, for example + interrupt handlers or other threads. Passing in 0 for *ms* will still allow + this other processing to occur. Use `sleep_us()` for more precise delays. + """ + ... + +def mktime(local_time: _TimeTuple, /) -> int: + """ + This is inverse function of localtime. It's argument is a full 8-tuple + which expresses a time as per localtime. It returns an integer which is + the number of seconds since the time epoch. + """ + ... + +def sleep(seconds: float, /) -> None: + """ + Sleep for the given number of seconds. Some boards may accept *seconds* as a + floating-point number to sleep for a fractional number of seconds. Note that + other boards may not accept a floating-point argument, for compatibility with + them use `sleep_ms()` and `sleep_us()` functions. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uarray.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uarray.pyi new file mode 100644 index 000000000..e5c0fe438 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uarray.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to array +from array import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uasyncio.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uasyncio.pyi new file mode 100644 index 000000000..3d69c52f2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uasyncio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to asyncio +from asyncio import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ubinascii.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ubinascii.pyi new file mode 100644 index 000000000..3a77380ad --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ubinascii.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to binascii +from binascii import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ubluetooth.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ubluetooth.pyi new file mode 100644 index 000000000..4046c2c75 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ubluetooth.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to bluetooth +from bluetooth import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ucollections.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ucollections.pyi new file mode 100644 index 000000000..b9d30f073 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ucollections.pyi @@ -0,0 +1,15 @@ +""" +Collection and container types. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/collections.html + +CPython module: :mod:`python:collections` https://docs.python.org/3/library/collections.html . + +This module implements advanced collection and container types to +hold/accumulate various objects. + +--- +Module: 'ucollections' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" +# import module from stdlib/module +from collections import * \ No newline at end of file diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ucryptolib.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ucryptolib.pyi new file mode 100644 index 000000000..6b8b56a68 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ucryptolib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to cryptolib +from cryptolib import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uctypes.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uctypes.pyi new file mode 100644 index 000000000..76f7e77ab --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uctypes.pyi @@ -0,0 +1,164 @@ +""" +Access binary data in a structured way. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/uctypes.html + +This module implements "foreign data interface" for MicroPython. The idea +behind it is similar to CPython's ``ctypes`` modules, but the actual API is +different, streamlined and optimized for small size. The basic idea of the +module is to define data structure layout with about the same power as the +C language allows, and then access it using familiar dot-syntax to reference +sub-fields. + +--- +Module: 'uctypes' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Tuple, Any, Final, Generator +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +VOID: Final[int] = 0 +"""\ +``VOID`` is an alias for ``UINT8``, and is provided to conveniently define +C's void pointers: ``(uctypes.PTR, uctypes.VOID)``. +""" +NATIVE: Final[int] = 2 +"""\ +Layout type for a native structure - with data endianness and alignment +conforming to the ABI of the system on which MicroPython runs. +""" +PTR: Final[int] = 536870912 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +SHORT: Final[int] = 402653184 +LONGLONG: Final[int] = 939524096 +INT8: Final[int] = 134217728 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +LITTLE_ENDIAN: Final[int] = 0 +"""\ +Layout type for a little-endian packed structure. (Packed means that every +field occupies exactly as many bytes as defined in the descriptor, i.e. +the alignment is 1). +""" +LONG: Final[int] = 671088640 +UINT: Final[int] = 536870912 +ULONG: Final[int] = 536870912 +ULONGLONG: Final[int] = 805306368 +USHORT: Final[int] = 268435456 +UINT8: Final[int] = 0 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT16: Final[int] = 268435456 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT32: Final[int] = 536870912 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT64: Final[int] = 805306368 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT64: Final[int] = 939524096 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +BFUINT16: Final[int] = -805306368 +BFUINT32: Final[int] = -536870912 +BFUINT8: Final[int] = -1073741824 +BFINT8: Final[int] = -939524096 +ARRAY: Final[int] = -1073741824 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +BFINT16: Final[int] = -671088640 +BFINT32: Final[int] = -402653184 +BF_LEN: Final[int] = 22 +INT: Final[int] = 671088640 +INT16: Final[int] = 402653184 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT32: Final[int] = 671088640 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +FLOAT64: Final[int] = -134217728 +"""Floating-point types for structure descriptors.""" +BF_POS: Final[int] = 17 +BIG_ENDIAN: Final[int] = 1 +"""Layout type for a big-endian packed structure.""" +FLOAT32: Final[int] = -268435456 +"""Floating-point types for structure descriptors.""" +_property: TypeAlias = Incomplete +_descriptor: TypeAlias = Tuple | Dict + +def sizeof(struct: struct | _descriptor | dict, layout_type: int = NATIVE, /) -> int: + """ + Return size of data structure in bytes. The *struct* argument can be + either a structure class or a specific instantiated structure object + (or its aggregate field). + """ + ... + +def bytes_at(addr: int, size: int, /) -> bytes: + """ + Capture memory at the given address and size as bytes object. As bytes + object is immutable, memory is actually duplicated and copied into + bytes object, so if memory contents change later, created object + retains original value. + """ + ... + +def bytearray_at(addr: int, size: int, /) -> bytearray: + """ + Capture memory at the given address and size as bytearray object. + Unlike bytes_at() function above, memory is captured by reference, + so it can be both written too, and you will access current value + at the given memory address. + """ + ... + +def addressof(obj: AnyReadableBuf, /) -> int: + """ + Return address of an object. Argument should be bytes, bytearray or + other object supporting buffer protocol (and address of this buffer + is what actually returned). + """ + ... + +class struct: + """ + Module contents + --------------- + """ + def __init__(self, addr: int | struct, descriptor: _descriptor, layout_type: int = NATIVE, /) -> None: + """ + Instantiate a "foreign data structure" object based on structure address in + memory, descriptor (encoded as a dictionary), and layout type (see below). + """ + ... + @mp_available() # force push + def __getattr__(self, a): ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uerrno.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uerrno.pyi new file mode 100644 index 000000000..8d34ba6b7 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uerrno.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to errno +from errno import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uhashlib.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uhashlib.pyi new file mode 100644 index 000000000..8b4b7bc77 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uhashlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to hashlib +from hashlib import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uheapq.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uheapq.pyi new file mode 100644 index 000000000..71c066fcf --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uheapq.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to heapq +from heapq import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uio.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uio.pyi new file mode 100644 index 000000000..514a4f945 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to io +from io import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ujson.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ujson.pyi new file mode 100644 index 000000000..0de669254 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ujson.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to json +from json import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/umachine.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/umachine.pyi new file mode 100644 index 000000000..e1fdb35a4 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/umachine.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to machine +from machine import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uos.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uos.pyi new file mode 100644 index 000000000..8c99e764b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uos.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to os +from os import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uplatform.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uplatform.pyi new file mode 100644 index 000000000..22ad247bf --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uplatform.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to platform +from platform import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/urandom.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/urandom.pyi new file mode 100644 index 000000000..b912f0793 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/urandom.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to random +from random import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ure.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ure.pyi new file mode 100644 index 000000000..dbe8b6a52 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ure.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to re +from re import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usb/device.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usb/device.pyi new file mode 100644 index 000000000..467e898ef --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usb/device.pyi @@ -0,0 +1,10 @@ +""" +Module: 'usb.device' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def get(*args, **kwargs) -> Incomplete: ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usb/device/cdc.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usb/device/cdc.pyi new file mode 100644 index 000000000..a95da0691 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usb/device/cdc.pyi @@ -0,0 +1,77 @@ +""" +Module: 'usb.device.cdc' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +_STOP_BITS_REPR: tuple = () +_PARITY_BITS_REPR: Final[str] = "NOEMS" + +def split_bmRequestType(*args, **kwargs) -> Incomplete: ... +def const(*args, **kwargs) -> Incomplete: ... + +class Buffer: + def finish_read(self, *args, **kwargs) -> Incomplete: ... + def pend_write(self, *args, **kwargs) -> Incomplete: ... + def finish_write(self, *args, **kwargs) -> Incomplete: ... + def pend_read(self, *args, **kwargs) -> Incomplete: ... + def readable(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def writable(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Interface: + def on_interface_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def stall(self, *args, **kwargs) -> Incomplete: ... + def on_device_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def xfer_pending(self, *args, **kwargs) -> Incomplete: ... + def on_endpoint_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def is_open(self, *args, **kwargs) -> Incomplete: ... + def num_itfs(self, *args, **kwargs) -> Incomplete: ... + def submit_xfer(self, *args, **kwargs) -> Incomplete: ... + def desc_cfg(self, *args, **kwargs) -> Incomplete: ... + def on_reset(self, *args, **kwargs) -> Incomplete: ... + def num_eps(self, *args, **kwargs) -> Incomplete: ... + def on_open(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class CDCInterface: + def xfer_pending(self, *args, **kwargs) -> Incomplete: ... + def is_open(self, *args, **kwargs) -> Incomplete: ... + def stall(self, *args, **kwargs) -> Incomplete: ... + def _readinto(self, *args, **kwargs) -> Incomplete: ... + def on_device_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def on_endpoint_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def on_interface_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def _wr_cb(self, *args, **kwargs) -> Incomplete: ... + def _wr_xfer(self, *args, **kwargs) -> Incomplete: ... + def _rd_cb(self, *args, **kwargs) -> Incomplete: ... + def set_break_cb(self, *args, **kwargs) -> Incomplete: ... + def set_line_state_cb(self, *args, **kwargs) -> Incomplete: ... + def _rd_xfer(self, *args, **kwargs) -> Incomplete: ... + def set_line_coding_cb(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def submit_xfer(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def num_eps(self, *args, **kwargs) -> Incomplete: ... + def desc_cfg(self, *args, **kwargs) -> Incomplete: ... + def num_itfs(self, *args, **kwargs) -> Incomplete: ... + def on_reset(self, *args, **kwargs) -> Incomplete: ... + def on_open(self, *args, **kwargs) -> Incomplete: ... + + baudrate: Incomplete ## = + rts: Incomplete ## = + parity: Incomplete ## = + dtr: Incomplete ## = + stop_bits: Incomplete ## = + data_bits: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uselect.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uselect.pyi new file mode 100644 index 000000000..a543041c4 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uselect.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to select +from select import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usocket.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usocket.pyi new file mode 100644 index 000000000..140590c29 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to socket +from socket import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ussl.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ussl.pyi new file mode 100644 index 000000000..3115761c4 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ussl.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to ssl +from ssl import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ustruct.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ustruct.pyi new file mode 100644 index 000000000..0f7fb657a --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ustruct.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to struct +from struct import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usys.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usys.pyi new file mode 100644 index 000000000..298d7a8ac --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/usys.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to sys +from sys import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/utime.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/utime.pyi new file mode 100644 index 000000000..1f972a5b6 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/utime.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to time +from time import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uwebsocket.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uwebsocket.pyi new file mode 100644 index 000000000..afa801ba2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uwebsocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to websocket +from websocket import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uzlib.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uzlib.pyi new file mode 100644 index 000000000..5fad9a23c --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/uzlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to zlib +from zlib import * diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/vfs.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/vfs.pyi new file mode 100644 index 000000000..6f915de3f --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/vfs.pyi @@ -0,0 +1,240 @@ +""" +Virtual filesystem control. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/vfs.html + +The ``vfs`` module contains functions for creating filesystem objects and +mounting/unmounting them in the Virtual Filesystem. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +--- +Module: 'vfs' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _BlockDeviceProtocol +from abc import ABC, abstractmethod +from typing import List, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def umount(mount_point: Incomplete) -> Incomplete: + """ + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + """ + ... + +@overload +def mount(fsobj, mount_point: str, *, readonly: bool = False) -> None: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +@overload +def mount() -> List[tuple[Incomplete, str]]: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +class VfsLfs2: + """ + Create a filesystem object that uses the `littlefs v2 filesystem format`_. + Storage of the littlefs filesystem is provided by *block_dev*, which must + support the :ref:`extended interface `. + Objects created by this constructor can be mounted using :func:`mount`. + + The *mtime* argument enables modification timestamps for files, stored using + littlefs attributes. This option can be disabled or enabled differently each + mount time and timestamps will only be added or updated if *mtime* is enabled, + otherwise the timestamps will remain untouched. Littlefs v2 filesystems without + timestamps will work without reformatting and timestamps will be added + transparently to existing files once they are opened for writing. When *mtime* + is enabled `os.stat` on files without timestamps will return 0 for the timestamp. + + See :ref:`filesystem` for more information. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32) -> None: + """ + Build a Lfs2 filesystem on *block_dev*. + + ``Note:`` There are reports of littlefs v2 failing in certain situations, + for details see `littlefs issue 295`_. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32, mtime=True) -> None: ... + +class VfsFat: + """ + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev) -> None: + """ + Build a FAT filesystem on *block_dev*. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev) -> None: ... + +class AbstractBlockDev: + # + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: ... + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + ... + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + ... + + @abstractmethod + @overload + def ioctl(self, op: int, arg) -> int | None: ... + # + @abstractmethod + @overload + def ioctl(self, op: int) -> int | None: + """ + Control the block device and query its parameters. The operation to + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 5 -- get the number of bytes in a block, should return an integer, + or ``None`` in which case the default value of 512 is used + (*arg* is unused) + - 6 -- erase a block, *arg* is the block number to erase + + As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs + ``ioctl(6, ...)`` must also be intercepted. The need for others is + hardware dependent. + + Prior to any call to ``writeblocks(block, ...)`` littlefs issues + ``ioctl(6, block)``. This enables a device driver to erase the block + prior to a write if the hardware requires it. Alternatively a driver + might intercept ``ioctl(6, block)`` and return 0 (success). In this case + the driver assumes responsibility for detecting the need for erasure. + + Unless otherwise stated ``ioctl(op, arg)`` can return ``None``. + Consequently an implementation can ignore unused values of ``op``. Where + ``op`` is intercepted, the return value for operations 4 and 5 are as + detailed above. Other operations should return 0 on success and non-zero + for failure, with the value returned being an ``OSError`` errno code. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/_onewire.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/_onewire.pyi new file mode 100644 index 000000000..20bb1a901 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/_onewire.pyi @@ -0,0 +1,15 @@ +""" +Module: '_onewire' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def reset(*args, **kwargs) -> Incomplete: ... +def writebyte(*args, **kwargs) -> Incomplete: ... +def writebit(*args, **kwargs) -> Incomplete: ... +def crc8(*args, **kwargs) -> Incomplete: ... +def readbyte(*args, **kwargs) -> Incomplete: ... +def readbit(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/binascii.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/binascii.pyi new file mode 100644 index 000000000..ce3060423 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/binascii.pyi @@ -0,0 +1,61 @@ +""" +Binary/ASCII conversions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/binascii.html + +CPython module: :mod:`python:binascii` https://docs.python.org/3/library/binascii.html . + +This module implements conversions between binary data and various +encodings of it in ASCII form (in both directions). + +--- +Module: 'binascii' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any, Optional +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def crc32(data, value: Optional[Any] = None) -> Incomplete: + """ + Compute CRC-32, the 32-bit checksum of *data*, starting with an initial CRC + of *value*. The default initial CRC is zero. The algorithm is consistent + with the ZIP file checksum. + """ + ... + +def hexlify(data: bytes, sep: str | bytes = ..., /) -> bytes: + """ + Convert the bytes in the *data* object to a hexadecimal representation. + Returns a bytes object. + + If the additional argument *sep* is supplied it is used as a separator + between hexadecimal values. + """ + ... + +def unhexlify(data: str | bytes, /) -> bytes: + """ + Convert hexadecimal data to binary representation. Returns bytes string. + (i.e. inverse of hexlify) + """ + ... + +def b2a_base64(data: bytes, /) -> bytes: + """ + Encode binary data in base64 format, as in `RFC 3548 + `_. Returns the encoded data + followed by a newline character if newline is true, as a bytes object. + """ + ... + +def a2b_base64(data: str | bytes, /) -> bytes: + """ + Decode base64-encoded data, ignoring invalid characters in the input. + Conforms to `RFC 2045 s.6.8 `_. + Returns a bytes object. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/cmath.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/cmath.pyi new file mode 100644 index 000000000..3dd30414a --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/cmath.pyi @@ -0,0 +1,84 @@ +""" +Mathematical functions for complex numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/cmath.html + +CPython module: :mod:`python:cmath` https://docs.python.org/3/library/cmath.html . + +The ``cmath`` module provides some basic mathematical functions for +working with complex numbers. + +Availability: not available on WiPy and ESP8266. Floating point support +required for this module. + +--- +Module: 'cmath' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsComplex, SupportsFloat, SupportsIndex, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_C: TypeAlias = SupportsFloat | SupportsComplex | SupportsIndex | complex + +e: float = 2.7182818 +"""base of the natural logarithm""" +pi: float = 3.1415928 +"""the ratio of a circle's circumference to its diameter""" + +def polar(z: _C, /) -> Tuple: + """ + Returns, as a tuple, the polar form of ``z``. + """ + ... + +def sqrt(z: _C, /) -> complex: + """ + Return the square-root of ``z``. + """ + ... + +def rect(r: float, phi: float, /) -> float: + """ + Returns the complex number with modulus ``r`` and phase ``phi``. + """ + ... + +def sin(z: _C, /) -> float: + """ + Return the sine of ``z``. + """ + ... + +def exp(z: _C, /) -> float: + """ + Return the exponential of ``z``. + """ + ... + +def cos(z: _C, /) -> float: + """ + Return the cosine of ``z``. + """ + ... + +def phase(z: _C, /) -> float: + """ + Returns the phase of the number ``z``, in the range (-pi, +pi]. + """ + ... + +def log(z: _C, /) -> float: + """ + Return the natural logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... + +def log10(z: _C, /) -> float: + """ + Return the base-10 logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/deflate.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/deflate.pyi new file mode 100644 index 000000000..6255589fe --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/deflate.pyi @@ -0,0 +1,89 @@ +""" +Deflate compression & decompression. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/deflate.html + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ +(commonly used in the zlib library and gzip archiver). + +**Availability:** + +* Added in MicroPython v1.21. + +* Decompression: Enabled via the ``MICROPY_PY_DEFLATE`` build option, on by default + on ports with the "extra features" level or higher (which is most boards). + +* Compression: Enabled via the ``MICROPY_PY_DEFLATE_COMPRESS`` build option, on + by default on ports with the "full features" level or higher (generally this means + you need to build your own firmware to enable this). + +--- +Module: 'deflate' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +GZIP: Final[int] = 3 +"""Supported values for the *format* parameter.""" +RAW: Final[int] = 1 +"""Supported values for the *format* parameter.""" +ZLIB: Final[int] = 2 +"""Supported values for the *format* parameter.""" +AUTO: Final[int] = 0 +"""Supported values for the *format* parameter.""" + +class DeflateIO: + """ + This class can be used to wrap a *stream* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + The *stream* must be a blocking stream. Non-blocking streams are currently + not supported. + + The *format* can be set to any of the constants defined below, and defaults + to ``AUTO`` which for decompressing will auto-detect gzip or zlib streams, + and for compressing it will generate a raw stream. + + The *wbits* parameter sets the base-2 logarithm of the DEFLATE dictionary + window size. So for example, setting *wbits* to ``10`` sets the window size + to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to + window sizes of 32 to 32k bytes). + + If *wbits* is set to ``0`` (the default), then for compression a window size + of 256 bytes will be used (as if *wbits* was set to 8). For decompression, it + depends on the format: + + * ``RAW`` will use 256 bytes (corresponding to *wbits* set to 8). + * ``ZLIB`` (or ``AUTO`` with zlib detected) will use the value from the zlib + header. + * ``GZIP`` (or ``AUTO`` with gzip detected) will use 32 kilobytes + (corresponding to *wbits* set to 15). + + See the :ref:`window size ` notes below for more information + about the window size, zlib, and gzip streams. + + If *close* is set to ``True`` then the underlying stream will be closed + automatically when the :class:`deflate.DeflateIO` stream is closed. This is + useful if you want to return a :class:`deflate.DeflateIO` stream that wraps + another stream and not have the caller need to know about managing the + underlying stream. + + If compression is enabled, a given :class:`deflate.DeflateIO` instance + supports both reading and writing. For example, a bidirectional stream like + a socket can be wrapped, which allows for compression/decompression in both + directions. + """ + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, stream, format=AUTO, wbits=0, close=False, /) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/dht.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/dht.pyi new file mode 100644 index 000000000..f6c87a348 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/dht.pyi @@ -0,0 +1,26 @@ +""" +Module: 'dht' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def dht_readinto(*args, **kwargs) -> Incomplete: ... + +class DHTBase: + def measure(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT22: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT11: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/doc_stubs.json b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/doc_stubs.json new file mode 100644 index 000000000..adcb4b944 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/doc_stubs.json @@ -0,0 +1,476 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "-", + "platform": "-", + "machine": "micropython", + "firmware": "micropython-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "documentation" + }, + "modules": [ + { + "file": "_thread/__init__.pyi", + "module": "__init__" + }, + { + "file": "array/__init__.pyi", + "module": "__init__" + }, + { + "file": "asyncio/__init__.pyi", + "module": "__init__" + }, + { + "file": "binascii/__init__.pyi", + "module": "__init__" + }, + { + "file": "bluetooth/__init__.pyi", + "module": "__init__" + }, + { + "file": "btree/__init__.pyi", + "module": "__init__" + }, + { + "file": "cmath/__init__.pyi", + "module": "__init__" + }, + { + "file": "collections/__init__.pyi", + "module": "__init__" + }, + { + "file": "cryptolib/__init__.pyi", + "module": "__init__" + }, + { + "file": "deflate/__init__.pyi", + "module": "__init__" + }, + { + "file": "errno/__init__.pyi", + "module": "__init__" + }, + { + "file": "esp/__init__.pyi", + "module": "__init__" + }, + { + "file": "esp32/__init__.pyi", + "module": "__init__" + }, + { + "file": "espnow/__init__.pyi", + "module": "__init__" + }, + { + "file": "framebuf/__init__.pyi", + "module": "__init__" + }, + { + "file": "gc/__init__.pyi", + "module": "__init__" + }, + { + "file": "gzip/__init__.pyi", + "module": "__init__" + }, + { + "file": "hashlib/__init__.pyi", + "module": "__init__" + }, + { + "file": "heapq/__init__.pyi", + "module": "__init__" + }, + { + "file": "io/__init__.pyi", + "module": "__init__" + }, + { + "file": "json/__init__.pyi", + "module": "__init__" + }, + { + "file": "lcd160cr/__init__.pyi", + "module": "__init__" + }, + { + "file": "machine/ADC.pyi", + "module": "ADC" + }, + { + "file": "machine/ADCBlock.pyi", + "module": "ADCBlock" + }, + { + "file": "machine/ADCWiPy.pyi", + "module": "ADCWiPy" + }, + { + "file": "machine/Counter.pyi", + "module": "Counter" + }, + { + "file": "machine/Encoder.pyi", + "module": "Encoder" + }, + { + "file": "machine/I2C.pyi", + "module": "I2C" + }, + { + "file": "machine/I2CTarget.pyi", + "module": "I2CTarget" + }, + { + "file": "machine/I2S.pyi", + "module": "I2S" + }, + { + "file": "machine/PWM.pyi", + "module": "PWM" + }, + { + "file": "machine/Pin.pyi", + "module": "Pin" + }, + { + "file": "machine/RTC.pyi", + "module": "RTC" + }, + { + "file": "machine/SD.pyi", + "module": "SD" + }, + { + "file": "machine/SDCard.pyi", + "module": "SDCard" + }, + { + "file": "machine/SPI.pyi", + "module": "SPI" + }, + { + "file": "machine/Signal.pyi", + "module": "Signal" + }, + { + "file": "machine/Timer.pyi", + "module": "Timer" + }, + { + "file": "machine/TimerWiPy.pyi", + "module": "TimerWiPy" + }, + { + "file": "machine/UART.pyi", + "module": "UART" + }, + { + "file": "machine/USBDevice.pyi", + "module": "USBDevice" + }, + { + "file": "machine/WDT.pyi", + "module": "WDT" + }, + { + "file": "machine/__init__.pyi", + "module": "__init__" + }, + { + "file": "marshal/__init__.pyi", + "module": "__init__" + }, + { + "file": "math/__init__.pyi", + "module": "__init__" + }, + { + "file": "micropython/__init__.pyi", + "module": "__init__" + }, + { + "file": "neopixel/__init__.pyi", + "module": "__init__" + }, + { + "file": "network/LAN.pyi", + "module": "LAN" + }, + { + "file": "network/PPP.pyi", + "module": "PPP" + }, + { + "file": "network/WIZNET5K.pyi", + "module": "WIZNET5K" + }, + { + "file": "network/WLAN.pyi", + "module": "WLAN" + }, + { + "file": "network/WLANWiPy.pyi", + "module": "WLANWiPy" + }, + { + "file": "network/__init__.pyi", + "module": "__init__" + }, + { + "file": "openamp/__init__.pyi", + "module": "__init__" + }, + { + "file": "os/__init__.pyi", + "module": "__init__" + }, + { + "file": "platform/__init__.pyi", + "module": "__init__" + }, + { + "file": "pyb/ADC.pyi", + "module": "ADC" + }, + { + "file": "pyb/Accel.pyi", + "module": "Accel" + }, + { + "file": "pyb/CAN.pyi", + "module": "CAN" + }, + { + "file": "pyb/DAC.pyi", + "module": "DAC" + }, + { + "file": "pyb/ExtInt.pyi", + "module": "ExtInt" + }, + { + "file": "pyb/Flash.pyi", + "module": "Flash" + }, + { + "file": "pyb/I2C.pyi", + "module": "I2C" + }, + { + "file": "pyb/LCD.pyi", + "module": "LCD" + }, + { + "file": "pyb/LED.pyi", + "module": "LED" + }, + { + "file": "pyb/Pin.pyi", + "module": "Pin" + }, + { + "file": "pyb/RTC.pyi", + "module": "RTC" + }, + { + "file": "pyb/SPI.pyi", + "module": "SPI" + }, + { + "file": "pyb/Servo.pyi", + "module": "Servo" + }, + { + "file": "pyb/Switch.pyi", + "module": "Switch" + }, + { + "file": "pyb/Timer.pyi", + "module": "Timer" + }, + { + "file": "pyb/UART.pyi", + "module": "UART" + }, + { + "file": "pyb/USB_HID.pyi", + "module": "USB_HID" + }, + { + "file": "pyb/USB_VCP.pyi", + "module": "USB_VCP" + }, + { + "file": "pyb/__init__.pyi", + "module": "__init__" + }, + { + "file": "random/__init__.pyi", + "module": "__init__" + }, + { + "file": "rp2/DMA.pyi", + "module": "DMA" + }, + { + "file": "rp2/Flash.pyi", + "module": "Flash" + }, + { + "file": "rp2/PIO.pyi", + "module": "PIO" + }, + { + "file": "rp2/StateMachine.pyi", + "module": "StateMachine" + }, + { + "file": "rp2/__init__.pyi", + "module": "__init__" + }, + { + "file": "select/__init__.pyi", + "module": "__init__" + }, + { + "file": "socket/__init__.pyi", + "module": "__init__" + }, + { + "file": "ssl/__init__.pyi", + "module": "__init__" + }, + { + "file": "stm/__init__.pyi", + "module": "__init__" + }, + { + "file": "struct/__init__.pyi", + "module": "__init__" + }, + { + "file": "sys/__init__.pyi", + "module": "__init__" + }, + { + "file": "time/__init__.pyi", + "module": "__init__" + }, + { + "file": "uarray.pyi", + "module": "uarray" + }, + { + "file": "uasyncio.pyi", + "module": "uasyncio" + }, + { + "file": "ubinascii.pyi", + "module": "ubinascii" + }, + { + "file": "ubluetooth.pyi", + "module": "ubluetooth" + }, + { + "file": "uctypes/__init__.pyi", + "module": "__init__" + }, + { + "file": "uerrno.pyi", + "module": "uerrno" + }, + { + "file": "uio.pyi", + "module": "uio" + }, + { + "file": "ujson.pyi", + "module": "ujson" + }, + { + "file": "umachine.pyi", + "module": "umachine" + }, + { + "file": "uos.pyi", + "module": "uos" + }, + { + "file": "uplatform.pyi", + "module": "uplatform" + }, + { + "file": "uselect.pyi", + "module": "uselect" + }, + { + "file": "usocket.pyi", + "module": "usocket" + }, + { + "file": "ussl.pyi", + "module": "ussl" + }, + { + "file": "ustruct.pyi", + "module": "ustruct" + }, + { + "file": "usys.pyi", + "module": "usys" + }, + { + "file": "utime.pyi", + "module": "utime" + }, + { + "file": "uzlib.pyi", + "module": "uzlib" + }, + { + "file": "vfs/__init__.pyi", + "module": "__init__" + }, + { + "file": "wipy/__init__.pyi", + "module": "__init__" + }, + { + "file": "wm8960/__init__.pyi", + "module": "__init__" + }, + { + "file": "zephyr/DiskAccess.pyi", + "module": "DiskAccess" + }, + { + "file": "zephyr/FlashArea.pyi", + "module": "FlashArea" + }, + { + "file": "zephyr/__init__.pyi", + "module": "__init__" + }, + { + "file": "zephyr/zsensor.pyi", + "module": "zsensor" + }, + { + "file": "zlib/__init__.pyi", + "module": "__init__" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ds18x20.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ds18x20.pyi new file mode 100644 index 000000000..96f095cd9 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ds18x20.pyi @@ -0,0 +1,18 @@ +""" +Module: 'ds18x20' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def const(*args, **kwargs) -> Incomplete: ... + +class DS18X20: + def read_scratch(self, *args, **kwargs) -> Incomplete: ... + def read_temp(self, *args, **kwargs) -> Incomplete: ... + def write_scratch(self, *args, **kwargs) -> Incomplete: ... + def convert_temp(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/errno.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/errno.pyi new file mode 100644 index 000000000..4bd9127a3 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/errno.pyi @@ -0,0 +1,97 @@ +""" +System error codes. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/errno.html + +CPython module: :mod:`python:errno` https://docs.python.org/3/library/errno.html . + +This module provides access to symbolic error codes for `OSError` exception. +A particular inventory of codes depends on :term:`MicroPython port`. + +--- +Module: 'errno' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +ENOBUFS: Final[int] = 105 +"""No buffer space available""" +ENODEV: Final[int] = 19 +"""No such device""" +ENOENT: Final[int] = 2 +"""No such file or directory""" +EISDIR: Final[int] = 21 +"""Is a directory""" +EIO: Final[int] = 5 +"""I/O error""" +EINVAL: Final[int] = 22 +"""Invalid argument""" +EPERM: Final[int] = 1 +"""Operation not permitted""" +ETIMEDOUT: Final[int] = 116 +"""Connection timed out""" +ENOMEM: Final[int] = 12 +"""Out of memory""" +EOPNOTSUPP: Final[int] = 95 +"""Operation not supported""" +ENOTCONN: Final[int] = 128 +"""Transport endpoint is not connected""" +errorcode: dict = {} +"""\ +Dictionary mapping numeric error codes to strings with symbolic error +code (see above):: + +>>> print(errno.errorcode[errno.EEXIST]) +EEXIST +""" +EAGAIN: Final[int] = 11 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EALREADY: Final[int] = 120 +"""Operation already in progress""" +EBADF: Final[int] = 9 +"""Bad file descriptor""" +EADDRINUSE: Final[int] = 112 +"""Address already in use""" +EACCES: Final[int] = 13 +"""Permission denied""" +EINPROGRESS: Final[int] = 119 +"""Operation now in progress""" +EEXIST: Final[int] = 17 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EHOSTUNREACH: Final[int] = 118 +"""Host is unreachable""" +ECONNABORTED: Final[int] = 113 +"""Connection aborted""" +ECONNRESET: Final[int] = 104 +"""Connection reset by peer""" +ECONNREFUSED: Final[int] = 111 +"""Connection refused""" +ENOTSUP: Final[int] = ... +"""Operation not supported""" diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/firmware_stubs.json b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/firmware_stubs.json new file mode 100644 index 000000000..edfe28f22 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/firmware_stubs.json @@ -0,0 +1,69 @@ +{"firmware": {"variant": "", "build": "", "arch": "armv7emsp", "port": "mimxrt", "board": "MIMXRT1010_EVK", "board_id": "MIMXRT1010_EVK", "mpy": "v6.3", "ver": "1.26.1", "family": "micropython", "cpu": "MIMXRT1011DAE5A", "version": "1.26.1"}, +"stubber": {"version": "v1.26.3"}, "stubtype": "firmware", +"modules" :[ +{"module": "_asyncio", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_asyncio.pyi"}, +{"module": "_onewire", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_onewire.pyi"}, +{"module": "array", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/array.pyi"}, +{"module": "asyncio.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/__init__.pyi"}, +{"module": "asyncio.core", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/core.pyi"}, +{"module": "asyncio.event", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/event.pyi"}, +{"module": "asyncio.funcs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/funcs.pyi"}, +{"module": "asyncio.lock", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/lock.pyi"}, +{"module": "asyncio.stream", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/stream.pyi"}, +{"module": "binascii", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/binascii.pyi"}, +{"module": "builtins", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/builtins.pyi"}, +{"module": "cmath", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/cmath.pyi"}, +{"module": "collections", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/collections.pyi"}, +{"module": "deflate", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/deflate.pyi"}, +{"module": "dht", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/dht.pyi"}, +{"module": "ds18x20", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ds18x20.pyi"}, +{"module": "errno", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/errno.pyi"}, +{"module": "framebuf", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/framebuf.pyi"}, +{"module": "gc", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/gc.pyi"}, +{"module": "hashlib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/hashlib.pyi"}, +{"module": "heapq", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/heapq.pyi"}, +{"module": "io", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/io.pyi"}, +{"module": "json", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/json.pyi"}, +{"module": "machine", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/machine.pyi"}, +{"module": "math", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/math.pyi"}, +{"module": "micropython", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/micropython.pyi"}, +{"module": "mimxrt", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/mimxrt.pyi"}, +{"module": "network", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/network.pyi"}, +{"module": "onewire", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/onewire.pyi"}, +{"module": "os", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/os.pyi"}, +{"module": "platform", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/platform.pyi"}, +{"module": "random", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/random.pyi"}, +{"module": "select", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/select.pyi"}, +{"module": "socket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/socket.pyi"}, +{"module": "struct", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/struct.pyi"}, +{"module": "sys", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/sys.pyi"}, +{"module": "time", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/time.pyi"}, +{"module": "uarray", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uarray.pyi"}, +{"module": "uasyncio.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/__init__.pyi"}, +{"module": "uasyncio.core", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/core.pyi"}, +{"module": "uasyncio.event", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/event.pyi"}, +{"module": "uasyncio.funcs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/funcs.pyi"}, +{"module": "uasyncio.lock", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/lock.pyi"}, +{"module": "uasyncio.stream", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/stream.pyi"}, +{"module": "ubinascii", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ubinascii.pyi"}, +{"module": "ucollections", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ucollections.pyi"}, +{"module": "uctypes", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uctypes.pyi"}, +{"module": "uerrno", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uerrno.pyi"}, +{"module": "uhashlib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uhashlib.pyi"}, +{"module": "uheapq", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uheapq.pyi"}, +{"module": "uio", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uio.pyi"}, +{"module": "ujson", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ujson.pyi"}, +{"module": "umachine", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/umachine.pyi"}, +{"module": "uos", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uos.pyi"}, +{"module": "uplatform", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uplatform.pyi"}, +{"module": "urandom", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/urandom.pyi"}, +{"module": "ure", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ure.pyi"}, +{"module": "usb.device", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device.pyi"}, +{"module": "usb.device.cdc", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device/cdc.pyi"}, +{"module": "uselect", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uselect.pyi"}, +{"module": "usocket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usocket.pyi"}, +{"module": "ustruct", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ustruct.pyi"}, +{"module": "usys", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usys.pyi"}, +{"module": "utime", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/utime.pyi"}, +{"module": "vfs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/vfs.pyi"} +]} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/framebuf.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/framebuf.pyi new file mode 100644 index 000000000..6f252c067 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/framebuf.pyi @@ -0,0 +1,247 @@ +""" +Frame buffer manipulation. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/framebuf.html + +This module provides a general frame buffer which can be used to create +bitmap images, which can then be sent to a display. + +--- +Module: 'framebuf' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Optional, Union, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +MONO_HMSB: Final[int] = 4 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +MONO_HLSB: Final[int] = 3 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +RGB565: Final[int] = 1 +"""Red Green Blue (16-bit, 5+6+5) color format""" +MONO_VLSB: Final[int] = 0 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are vertically mapped with +bit 0 being nearest the top of the screen. Consequently each byte occupies +8 vertical pixels. Subsequent bytes appear at successive horizontal +locations until the rightmost edge is reached. Further bytes are rendered +at locations starting at the leftmost edge, 8 pixels lower. +""" +MVLSB: Final[int] = 0 +GS2_HMSB: Final[int] = 5 +"""Grayscale (2-bit) color format""" +GS8: Final[int] = 6 +"""Grayscale (8-bit) color format""" +GS4_HMSB: Final[int] = 2 +"""Grayscale (4-bit) color format""" + +def FrameBuffer1(*args, **kwargs) -> Incomplete: ... + +class FrameBuffer: + """ + The FrameBuffer class provides a pixel buffer which can be drawn upon with + pixels, lines, rectangles, text and even other FrameBuffer's. It is useful + when generating output for displays. + + For example:: + + import framebuf + + # FrameBuffer needs 2 bytes for every RGB565 pixel + fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565) + + fbuf.fill(0) + fbuf.text('MicroPython!', 0, 0, 0xffff) + fbuf.hline(0, 9, 96, 0xffff) + """ + def poly(self, x, y, coords, c, f: Union[bool, int] = False, /) -> Incomplete: + """ + Given a list of coordinates, draw an arbitrary (convex or concave) closed + polygon at the given x, y location using the given color. + + The *coords* must be specified as a :mod:`array` of integers, e.g. + ``array('h', [x0, y0, x1, y1, ... xn, yn])``. + + The optional *f* parameter can be set to ``True`` to fill the polygon. + Otherwise just a one pixel outline is drawn. + """ + ... + def vline(self, x: int, y: int, h: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + + @overload + def pixel(self, x: int, y: int, /) -> int: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + + @overload + def pixel(self, x: int, y: int, c: int, /) -> None: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + def text(self, s: str, x: int, y: int, c: int = 1, /) -> None: + """ + Write text to the FrameBuffer using the coordinates as the upper-left + corner of the text. The color of the text can be defined by the optional + argument but is otherwise a default value of 1. All characters have + dimensions of 8x8 pixels and there is currently no way to change the font. + """ + ... + def rect(self, x: int, y: int, w: int, h: int, c: int, f: Union[bool, int] = False, /) -> None: + """ + Draw a rectangle at the given location, size and color. + + The optional *f* parameter can be set to ``True`` to fill the rectangle. + Otherwise just a one pixel outline is drawn. + """ + ... + def scroll(self, xstep: int, ystep: int, /) -> None: + """ + Shift the contents of the FrameBuffer by the given vector. This may + leave a footprint of the previous colors in the FrameBuffer. + """ + ... + def ellipse(self, x, y, xr, yr, c, f: Union[bool, int] = False, m: Optional[int] = None) -> None: + """ + Draw an ellipse at the given location. Radii *xr* and *yr* define the + geometry; equal values cause a circle to be drawn. The *c* parameter + defines the color. + + The optional *f* parameter can be set to ``True`` to fill the ellipse. + Otherwise just a one pixel outline is drawn. + + The optional *m* parameter enables drawing to be restricted to certain + quadrants of the ellipse. The LS four bits determine which quadrants are + to be drawn, with bit 0 specifying Q1, b1 Q2, b2 Q3 and b3 Q4. Quadrants + are numbered counterclockwise with Q1 being top right. + """ + ... + def line(self, x1: int, y1: int, x2: int, y2: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def blit( + self, + fbuf: FrameBuffer, + x: int, + y: int, + key: int = -1, + palette: Optional[bytes] = None, + /, + ) -> None: + """ + Draw another FrameBuffer on top of the current one at the given coordinates. + If *key* is specified then it should be a color integer and the + corresponding color will be considered transparent: all pixels with that + color value will not be drawn. (If the *palette* is specified then the *key* + is compared to the value from *palette*, not to the value directly from + *fbuf*.) + + *fbuf* can be another FrameBuffer instance, or a tuple or list of the form:: + + (buffer, width, height, format) + + or:: + + (buffer, width, height, format, stride) + + This matches the signature of the FrameBuffer constructor, and the elements + of the tuple/list are the same as the arguments to the constructor except that + the *buffer* here can be read-only. + + The *palette* argument enables blitting between FrameBuffers with differing + formats. Typical usage is to render a monochrome or grayscale glyph/icon to + a color display. The *palette* is a FrameBuffer instance whose format is + that of the current FrameBuffer. The *palette* height is one pixel and its + pixel width is the number of colors in the source FrameBuffer. The *palette* + for an N-bit source needs 2**N pixels; the *palette* for a monochrome source + would have 2 pixels representing background and foreground colors. The + application assigns a color to each pixel in the *palette*. The color of the + current pixel will be that of that *palette* pixel whose x position is the + color of the corresponding source pixel. + """ + ... + def hline(self, x: int, y: int, w: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def fill(self, c: int, /) -> None: + """ + Fill the entire FrameBuffer with the specified color. + """ + ... + def fill_rect(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + buffer: AnyWritableBuf, + width: int, + height: int, + format: int, + stride: int = ..., + /, + ) -> None: + """ + Construct a FrameBuffer object. The parameters are: + + - *buffer* is an object with a buffer protocol which must be large + enough to contain every pixel defined by the width, height and + format of the FrameBuffer. + - *width* is the width of the FrameBuffer in pixels + - *height* is the height of the FrameBuffer in pixels + - *format* specifies the type of pixel used in the FrameBuffer; + permissible values are listed under Constants below. These set the + number of bits used to encode a color value and the layout of these + bits in *buffer*. + Where a color value c is passed to a method, c is a small integer + with an encoding that is dependent on the format of the FrameBuffer. + - *stride* is the number of pixels between each horizontal line + of pixels in the FrameBuffer. This defaults to *width* but may + need adjustments when implementing a FrameBuffer within another + larger FrameBuffer or screen. The *buffer* size must accommodate + an increased step size. + + One must specify valid *buffer*, *width*, *height*, *format* and + optionally *stride*. Invalid *buffer* size or dimensions may lead to + unexpected errors. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/gc.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/gc.pyi new file mode 100644 index 000000000..026e42f51 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/gc.pyi @@ -0,0 +1,112 @@ +""" +Control the garbage collector. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/gc.html + +CPython module: :mod:`python:gc` https://docs.python.org/3/library/gc.html . + +--- +Module: 'gc' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def mem_alloc() -> int: + """ + Return the number of bytes of heap RAM that are allocated by Python code. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +def isenabled(*args, **kwargs) -> Incomplete: ... +def mem_free() -> int: + """ + Return the number of bytes of heap RAM that is available for Python + code to allocate, or -1 if this amount is not known. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +@overload +def threshold() -> int: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +@overload +def threshold(amount: int) -> None: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +def collect() -> None: + """ + Run a garbage collection. + """ + ... + +def enable() -> None: + """ + Enable automatic garbage collection. + """ + ... + +def disable() -> None: + """ + Disable automatic garbage collection. Heap memory can still be allocated, + and garbage collection can still be initiated manually using :meth:`gc.collect`. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/hashlib.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/hashlib.pyi new file mode 100644 index 000000000..072dc8874 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/hashlib.pyi @@ -0,0 +1,94 @@ +""" +Hashing algorithms. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/hashlib.html + +CPython module: :mod:`python:hashlib` https://docs.python.org/3/library/hashlib.html . + +This module implements binary data hashing algorithms. The exact inventory +of available algorithms depends on a board. Among the algorithms which may +be implemented: + +* SHA256 - The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + +* SHA1 - A previous generation algorithm. Not recommended for new usages, + but SHA1 is a part of number of Internet standards and existing + applications, so boards targeting network connectivity and + interoperability will try to provide this. + +* MD5 - A legacy algorithm, not considered cryptographically secure. Only + selected boards, targeting interoperability with legacy applications, + will offer this. + +--- +Module: 'hashlib' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, _Hash +from typing import NoReturn, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated + +class sha256(_Hash): + """ + The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + +class sha1: + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/heapq.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/heapq.pyi new file mode 100644 index 000000000..ca4ae7591 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/heapq.pyi @@ -0,0 +1,46 @@ +""" +Heap queue algorithm. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/heapq.html + +CPython module: :mod:`python:heapq` https://docs.python.org/3/library/heapq.html . + +This module implements the +`min heap queue algorithm `_. + +A heap queue is essentially a list that has its elements stored in such a way +that the first item of the list is always the smallest. + +--- +Module: 'heapq' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +def heappop(heap: list[_T], /) -> _T: + """ + Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if + ``heap`` is empty. + + The returned item will be the smallest item in the ``heap``. + """ + ... + +def heappush(heap: list[_T], item: _T, /) -> None: + """ + Push the ``item`` onto the ``heap``. + """ + ... + +def heapify(x: list[Any], /) -> None: + """ + Convert the list ``x`` into a heap. This is an in-place operation. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/machine.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/machine.pyi new file mode 100644 index 000000000..6703bbc37 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/machine.pyi @@ -0,0 +1,3052 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. + +--- +Module: 'machine' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import NoReturn, Union, List, Sequence, Optional, Callable, Tuple, overload, Any, Final +from _typeshed import Incomplete +from typing_extensions import deprecated, Awaitable, TypeAlias, TypeVar +from _mpy_shed import mp_available, _IRQ, AnyReadableBuf, AnyWritableBuf +from vfs import AbstractBlockDev + +SOFT_RESET: Final[int] = 5 +"""Reset causes.""" +PWRON_RESET: Final[int] = 1 +"""Reset causes.""" +WDT_RESET: Final[int] = 3 +"""Reset causes.""" +ID_T: TypeAlias = int | str +ATTN_0DB: int = ... +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +HARD_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +def unique_id() -> bytes: + """ + Returns a byte string with a unique identifier of a board/SoC. It will vary + from a board/SoC instance to another, if underlying hardware allows. Length + varies by hardware (so use substring of a full value if you expect a short + ID). In some MicroPython ports, ID corresponds to the network MAC address. + """ + ... + +def disable_irq() -> _IRQ_STATE: + """ + Disable interrupt requests. + Returns the previous IRQ state which should be considered an opaque value. + This return value should be passed to the `enable_irq()` function to restore + interrupts to their original state, before `disable_irq()` was called. + """ + ... + +def dht_readinto(*args, **kwargs) -> Incomplete: ... +def bitstream(pin, encoding, timing, data, /) -> Incomplete: + """ + Transmits *data* by bit-banging the specified *pin*. The *encoding* argument + specifies how the bits are encoded, and *timing* is an encoding-specific timing + specification. + + The supported encodings are: + + - ``0`` for "high low" pulse duration modulation. This will transmit 0 and + 1 bits as timed pulses, starting with the most significant bit. + The *timing* must be a four-tuple of nanoseconds in the format + ``(high_time_0, low_time_0, high_time_1, low_time_1)``. For example, + ``(400, 850, 800, 450)`` is the timing specification for WS2812 RGB LEDs + at 800kHz. + + The accuracy of the timing varies between ports. On Cortex M0 at 48MHz, it is + at best +/- 120ns, however on faster MCUs (ESP8266, ESP32, STM32, Pyboard), it + will be closer to +/-30ns. + + ``Note:`` For controlling WS2812 / NeoPixel strips, see the :mod:`neopixel` + module for a higher-level API. + """ + ... + +def bootloader(value: Optional[Any] = None) -> None: + """ + Reset the device and enter its bootloader. This is typically used to put the + device into a state where it can be programmed with new firmware. + + Some ports support passing in an optional *value* argument which can control + which bootloader to enter, what to pass to it, or other things. + """ + ... + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +def enable_irq(state: _IRQ_STATE, /) -> None: + """ + Re-enable interrupt requests. + The *state* parameter should be the value that was returned from the most + recent call to the `disable_irq()` function. + """ + ... + +def reset_cause() -> int: + """ + Get the reset cause. See :ref:`constants ` for the possible return values. + """ + ... + +def soft_reset() -> NoReturn: + """ + Performs a :ref:`soft reset ` of the interpreter, deleting all + Python objects and resetting the Python heap. + """ + ... + +def time_pulse_us(pin: Pin, pulse_level: int, timeout_us: int = 1_000_000, /) -> int: + """ + Time a pulse on the given *pin*, and return the duration of the pulse in + microseconds. The *pulse_level* argument should be 0 to time a low pulse + or 1 to time a high pulse. + + If the current input value of the pin is different to *pulse_level*, + the function first (*) waits until the pin input becomes equal to *pulse_level*, + then (**) times the duration that the pin is equal to *pulse_level*. + If the pin is already equal to *pulse_level* then timing starts straight away. + + The function will return -2 if there was timeout waiting for condition marked + (*) above, and -1 if there was timeout during the main measurement, marked (**) + above. The timeout is the same for both cases and given by *timeout_us* (which + is in microseconds). + """ + ... + +def reset() -> NoReturn: + """ + :ref:`Hard resets ` the device in a manner similar to pushing the + external RESET button. + """ + ... + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +def idle() -> None: + """ + Gates the clock to the CPU, useful to reduce power consumption at any time + during short or long periods. Peripherals continue working and execution + resumes as soon as any interrupt is triggered, or at most one millisecond + after the CPU was paused. + + It is recommended to call this function inside any tight loop that is + continuously checking for an external change (i.e. polling). This will reduce + power consumption without significantly impacting performance. To reduce + power consumption further then see the :func:`lightsleep`, + :func:`time.sleep()` and :func:`time.sleep_ms()` functions. + """ + ... + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +mem8: Incomplete ## = <8-bit memory> +"""Read/write 8 bits of memory.""" +mem32: Incomplete ## = <32-bit memory> +"""\ +Read/write 32 bits of memory. + +Use subscript notation ``[...]`` to index these objects with the address of +interest. Note that the address is the byte address, regardless of the size of +memory being accessed. + +Example use (registers are specific to an stm32 microcontroller): +""" +mem16: Incomplete ## = <16-bit memory> +"""Read/write 16 bits of memory.""" + +class LED: + def on(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class WDT: + """ + The WDT 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 machine import WDT + wdt = WDT(timeout=2000) # enable it with a timeout of 2s + wdt.feed() + + Availability of this class: pyboard, WiPy, esp8266, esp32. + """ + def timeout_ms(self, *args, **kwargs) -> Incomplete: ... + def feed(self) -> None: + """ + Feed the WDT to prevent it from resetting the system. The application + should place this call in a sensible place ensuring that the WDT is + only fed after verifying that everything is functioning correctly. + """ + ... + def __init__(self, *, id: int = 0, timeout: int = 5000) -> None: + """ + Create a WDT object and start it. The timeout must be given in milliseconds. + Once it is running the timeout cannot be changed and the WDT cannot be stopped either. + + Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout + cannot be specified, it is determined by the underlying system. + """ + +class I2S: + """ + I2S is a synchronous serial protocol used to connect digital audio devices. + At the physical level, a bus consists of 3 lines: SCK, WS, SD. + The I2S class supports controller operation. Peripheral operation is not supported. + + The I2S class is currently available as a Technical Preview. During the preview period, feedback from + users is encouraged. Based on this feedback, the I2S class API and implementation may be changed. + + I2S objects can be created and initialized using:: + + from machine import I2S + from machine import Pin + + # ESP32 + sck_pin = Pin(14) # Serial clock output + ws_pin = Pin(13) # Word clock output + sd_pin = Pin(12) # Serial data output + + or + + # PyBoards + sck_pin = Pin("Y6") # Serial clock output + ws_pin = Pin("Y5") # Word clock output + sd_pin = Pin("Y8") # Serial data output + + audio_out = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.TX, + bits=16, + format=I2S.MONO, + rate=44100, + ibuf=20000) + + audio_in = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.RX, + bits=32, + format=I2S.STEREO, + rate=22050, + ibuf=20000) + + 3 modes of operation are supported: + - blocking + - non-blocking + - uasyncio + + blocking:: + + num_written = audio_out.write(buf) # blocks until buf emptied + + num_read = audio_in.readinto(buf) # blocks until buf filled + + non-blocking:: + + audio_out.irq(i2s_callback) # i2s_callback is called when buf is emptied + num_written = audio_out.write(buf) # returns immediately + + audio_in.irq(i2s_callback) # i2s_callback is called when buf is filled + num_read = audio_in.readinto(buf) # returns immediately + + uasyncio:: + + swriter = uasyncio.StreamWriter(audio_out) + swriter.write(buf) + await swriter.drain() + + sreader = uasyncio.StreamReader(audio_in) + num_read = await sreader.readinto(buf) + """ + + RX: Final[int] = 0 + """for initialising the I2S bus ``mode`` to receive""" + MONO: Final[int] = 0 + """for initialising the I2S bus ``format`` to mono""" + STEREO: Final[int] = 1 + """for initialising the I2S bus ``format`` to stereo""" + TX: Final[int] = 1 + """for initialising the I2S bus ``mode`` to transmit""" + @staticmethod + def shift( + buf: AnyWritableBuf, + bits: int, + shift: int, + /, + ) -> None: + """ + bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample. + Positive for left shift, negative for right shift. + Typically used for volume control. Each bit shift changes sample volume by 6dB. + """ + ... + def init( + self, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + see Constructor for argument descriptions + """ + ... + def irq( + self, + handler: Callable[[Any], None], + /, + ) -> None: + """ + Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method). + Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation. + ``handler`` is called in the context of the MicroPython scheduler. + """ + ... + def readinto( + self, + buf: AnyWritableBuf, + /, + ) -> int: + """ + Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the left channel sample data is used. + Returns number of bytes read + """ + ... + def deinit(self) -> None: + """ + Deinitialize the I2S bus + """ + ... + def write( + self, + buf: AnyReadableBuf, + /, + ) -> int: + """ + Write audio samples contained in ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the sample data is written to both the right and left channels. + Returns number of bytes written + """ + ... + def __init__( + self, + id: ID_T, + /, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + Construct an I2S object of the given id: + + - ``id`` identifies a particular I2S bus. + + ``id`` is board and port specific: + + - PYBv1.0/v1.1: has one I2S bus with id=2. + - PYBD-SFxW: has two I2S buses with id=1 and id=2. + - ESP32: has two I2S buses with id=0 and id=1. + + Keyword-only parameters that are supported on all ports: + + - ``sck`` is a pin object for the serial clock line + - ``ws`` is a pin object for the word select line + - ``sd`` is a pin object for the serial data line + - ``mode`` specifies receive or transmit + - ``bits`` specifies sample size (bits), 16 or 32 + - ``format`` specifies channel format, STEREO or MONO + - ``rate`` specifies audio sampling rate (samples/s) + - ``ibuf`` specifies internal buffer length (bytes) + + For all ports, DMA runs continuously in the background and allows user applications to perform other operations while + sample data is transfered between the internal buffer and the I2S peripheral unit. + Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations + before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method). + """ + +class ADC: + """ + The ADC class provides an interface to analog-to-digital convertors, and + represents a single endpoint that can sample a continuous voltage and + convert it to a discretised value. + + Example usage:: + + import machine + + adc = machine.ADC(pin) # create an ADC object acting on a pin + val = adc.read_u16() # read a raw analog value in the range 0-65535 + """ + + VREF: int = ... + CORE_VREF: int = ... + CORE_VBAT: int = ... + CORE_TEMP: int = ... + ATTN_0DB: int = 0 + ATTN_2_5DB: int = 1 + ATTN_6DB: int = 2 + ATTN_11DB: int = 3 + WIDTH_9BIT: int = 9 + WIDTH_10BIT: int = 10 + WIDTH_11BIT: int = 11 + WIDTH_12BIT: int = 12 + def read_uv(self) -> int: + """ + Take an analog reading and return an integer value with units of + microvolts. It is up to the particular port whether or not this value + is calibrated, and how calibration is done. + """ + ... + def read_u16(self) -> int: + """ + Take an analog reading and return an integer in the range 0-65535. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 65535. + """ + ... + def __init__(self, pin: PinLike, *, atten=ATTN_0DB) -> None: + """ + Access the ADC associated with a source identified by *id*. This + *id* may be an integer (usually specifying a channel number), a + :ref:`Pin ` object, or other value supported by the + underlying machine. + .. note:: + + WiPy has a custom implementation of ADC, see ADCWiPy for details. + + on ESP32 : `atten` specifies the attenuation level for the ADC input. + """ + + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class I2C: + """ + 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. + + I2C objects are created attached to a specific bus. They can be initialised + when created, or initialised later on. + + Printing the I2C object gives you information about its configuration. + + Both hardware and software I2C implementations exist via the + :ref:`machine.I2C ` and `machine.SoftI2C` classes. Hardware I2C uses + underlying hardware support of the system to perform the reads/writes and is + usually efficient and fast but may have restrictions on which pins can be used. + Software I2C is implemented by bit-banging and can be used on any pin but is not + as efficient. These classes have the same methods available and differ primarily + in the way they are constructed. + + Example usage:: + + from machine import I2C + + i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz + # depending on the port, extra parameters may be required + # to select the peripheral and/or pins to use + + i2c.scan() # scan for peripherals, returning a list of 7-bit addresses + + i2c.writeto(42, b'123') # write 3 bytes to peripheral with 7-bit address 42 + i2c.readfrom(42, 4) # read 4 bytes from peripheral with 7-bit address 42 + + i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of peripheral 42, + # starting at memory-address 8 in the peripheral + i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42 + # starting at address 2 in the peripheral + """ + def readfrom_mem_into(self, addr: int, memaddr: int, buf: AnyWritableBuf, /, *, addrsize: int = 8) -> None: + """ + Read into *buf* from the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. The number of bytes read is the + length of *buf*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def readfrom_into(self, addr: int, buf: AnyWritableBuf, stop: bool = True, /) -> None: + """ + Read into *buf* from the peripheral specified by *addr*. + The number of bytes read will be the length of *buf*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + + The method returns ``None``. + """ + ... + def readfrom_mem(self, addr: int, memaddr: int, nbytes: int, /, *, addrsize: int = 8) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr* starting from the memory + address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits. + Returns a `bytes` object with the data read. + """ + ... + def writeto_mem(self, addr: int, memaddr: int, buf: AnyReadableBuf, /, *, addrsize: int = 8) -> None: + """ + Write *buf* to the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def scan(self) -> List: + """ + 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 write bit) is sent on the bus. + """ + ... + def writeto(self, addr: int, buf: AnyReadableBuf, stop: bool = True, /) -> int: + """ + Write the bytes from *buf* to the peripheral specified by *addr*. If a + NACK is received following the write of a byte from *buf* then the + remaining bytes are not sent. If *stop* is true then a STOP condition is + generated at the end of the transfer, even if a NACK is received. + The function returns the number of ACKs that were received. + """ + ... + def writevto(self, addr: int, vector: Sequence[AnyReadableBuf], stop: bool = True, /) -> int: + """ + Write the bytes contained in *vector* to the peripheral specified by *addr*. + *vector* should be a tuple or list of objects with the buffer protocol. + The *addr* is sent once and then the bytes from each object in *vector* + are written out sequentially. The objects in *vector* may be zero bytes + in length in which case they don't contribute to the output. + + If a NACK is received following the write of a byte from one of the + objects in *vector* then the remaining bytes, and any remaining objects, + are not sent. If *stop* is true then a STOP condition is generated at + the end of the transfer, even if a NACK is received. The function + returns the number of ACKs that were received. + """ + ... + def start(self) -> None: + """ + Generate a START condition on the bus (SDA transitions to low while SCL is high). + """ + ... + def readfrom(self, addr: int, nbytes: int, stop: bool = True, /) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + Returns a `bytes` object with the data read. + """ + ... + def readinto(self, buf: AnyWritableBuf, nack: bool = True, /) -> None: + """ + Reads bytes from the bus and stores them into *buf*. The number of bytes + read is the length of *buf*. An ACK will be sent on the bus after + receiving all but the last byte. After the last byte is received, if *nack* + is true then a NACK will be sent, otherwise an ACK will be sent (and in this + case the peripheral assumes more bytes are going to be read in a later call). + """ + ... + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + def stop(self) -> None: + """ + Generate a STOP condition on the bus (SDA transitions to high while SCL is high). + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes from *buf* to the bus. Checks that an ACK is received + after each byte and stops transmitting the remaining bytes if a NACK is + received. The function returns the number of ACKs that were received. + """ + ... + + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class I2CTarget: + """ + Construct and return a new I2CTarget object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values depend on the + particular port/board. Some ports have a default in which case this parameter + can be omitted. + - *addr* is the I2C address of the target. + - *addrsize* is the number of bits in the I2C target address. Valid values + are 7 and 10. + - *mem* is an object with the buffer protocol that is writable. If not + specified then there is no backing memory and data must be read/written + using the :meth:`I2CTarget.readinto` and :meth:`I2CTarget.write` methods. + - *mem_addrsize* is the number of bits in the memory address. Valid values + are 0, 8, 16, 24 and 32. + - *scl* is a pin object specifying the pin to use for SCL. + - *sda* is a pin object specifying the pin to use for SDA. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + IRQ_END_READ: Final[int] = 16 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_WRITE: Final[int] = 2 + """IRQ trigger sources.""" + IRQ_END_WRITE: Final[int] = 32 + """IRQ trigger sources.""" + IRQ_READ_REQ: Final[int] = 4 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_READ: Final[int] = 1 + """IRQ trigger sources.""" + IRQ_WRITE_REQ: Final[int] = 8 + """IRQ trigger sources.""" + def deinit(self) -> Incomplete: + """ + Deinitialise the I2C target. After this method is called the hardware will no + longer respond to requests on the I2C bus, and no other methods can be called. + """ + ... + def irq(self, handler=None, trigger=IRQ_END_READ | IRQ_END_WRITE, hard=False) -> Incomplete: + """ + Configure an IRQ *handler* to be called when an event occurs. The possible events are + given by the following constants, which can be or'd together and passed to the *trigger* + argument: + + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a read transaction. + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a write transaction. + - ``IRQ_READ_REQ`` indicates that the controller is requesting data, and this + request must be satisfied by calling `I2CTarget.write` with the data to be + passed back to the controller. + - ``IRQ_WRITE_REQ`` indicates that the controller has written data, and the + data must be read by calling `I2CTarget.readinto`. + - ``IRQ_END_READ`` indicates that the controller has finished a read transaction. + - ``IRQ_END_WRITE`` indicates that the controller has finished a write transaction. + + Not all triggers are available on all ports. If a port has the constant then that + event is available. + + Note the following restrictions: + + - ``IRQ_ADDR_MATCH_READ``, ``IRQ_ADDR_MATCH_READ``, ``IRQ_READ_REQ`` and + ``IRQ_WRITE_REQ`` must be handled by a hard IRQ callback (with the *hard* argument + set to ``True``). This is because these events have very strict timing requirements + and must usually be satisfied synchronously with the hardware event. + + - ``IRQ_END_READ`` and ``IRQ_END_WRITE`` may be handled by either a soft or hard + IRQ callback (although note that all events must be registered with the same handler, + so if any events need a hard callback then all events must be hard). + + - If a memory buffer has been supplied in the constructor then ``IRQ_END_WRITE`` + is not emitted for the transaction that writes the memory address. This is to + allow ``IRQ_END_READ`` and ``IRQ_END_WRITE`` to function correctly as soft IRQ + callbacks, where the IRQ handler may be called quite some time after the actual + hardware event. + """ + ... + def write(self, buf) -> int: + """ + Write out the bytes from the given buffer, to be passed to the I2C controller + after it sends a read request. Returns the number of bytes written. Most ports + only accept one byte at a time to this method. + """ + ... + def readinto(self, buf) -> int: + """ + Read into the given buffer any pending bytes written by the I2C controller. + Returns the number of bytes read. + """ + ... + def __init__(self, id, addr, *, addrsize=7, mem=None, mem_addrsize=8, scl=None, sda=None) -> None: ... + +class SoftI2C(I2C): + """ + Construct a new software I2C object. The parameters are: + + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + - *timeout* is the maximum time in microseconds to wait for clock + stretching (SCL held low by another device on the bus), after + which an ``OSError(ETIMEDOUT)`` exception is raised. + """ + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, scl, sda, *, freq=400000, timeout=50000) -> None: ... + +class SoftSPI(SPI): + """ + Construct a new software SPI object. Additional parameters must be + given, usually at least *sck*, *mosi* and *miso*, and these are used + to initialise the bus. See `SPI.init` for a description of the parameters. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + baudrate=500000, + *, + polarity=0, + phase=0, + bits=8, + firstbit=MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: ... + +class Timer: + """ + Hardware timers deal with timing of periods and events. Timers are perhaps + the most flexible and heterogeneous kind of hardware in MCUs and SoCs, + differently greatly from a model to a model. MicroPython's Timer class + defines a baseline operation of executing a callback with a given period + (or once after some delay), and allow specific boards to define more + non-standard behaviour (which thus won't be portable to other boards). + + See discussion of :ref:`important constraints ` on + Timer callbacks. + + .. note:: + + Memory can't be allocated inside irq handlers (an interrupt) and so + exceptions raised within a handler don't give much information. See + :func:`micropython.alloc_emergency_exception_buf` for how to get around this + limitation. + + If you are using a WiPy board please refer to :ref:`machine.TimerWiPy ` + instead of this class. + """ + + PERIODIC: Final[int] = 2 + """Timer operating mode.""" + ONE_SHOT: Final[int] = 1 + """Timer operating mode.""" + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + def deinit(self) -> None: + """ + Deinitialises the timer. Stops the timer, and disables the timer peripheral. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + +class UART: + """ + UART implements the standard UART/USART duplex serial communications protocol. At + the physical level it consists of 2 lines: RX and TX. The unit of communication + is a character (not to be confused with a string character) which can be 8 or 9 + bits wide. + + UART objects can be created and initialised using:: + + from machine import UART + + uart = UART(1, 9600) # init with given baudrate + uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters + + Supported parameters differ on a board: + + Pyboard: Bits can be 7, 8 or 9. Stop can be 1 or 2. With *parity=None*, + only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits + are supported. + + WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2. + + A UART object acts like a `stream` object and reading and writing is done + using the standard stream methods:: + + uart.read(10) # read 10 characters, returns a bytes object + uart.read() # read all available characters + uart.readline() # read a line + uart.readinto(buf) # read and store into the given buffer + uart.write('abc') # write the 3 characters + """ + + INV_TX: Final[int] = 1 + INV_RX: Final[int] = 2 + CTS: Final[int] = 2 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RXIDLE: Final[int] = 1 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + IRQ_TXIDLE: Final[int] = 2 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + RTS: Final[int] = 1 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RX: Incomplete + IRQ_BREAK: Incomplete + IDLE: int = ... + def irq( + self, + handler: Callable[[UART], None] | None = None, + trigger: int = 0, + hard: bool = False, + /, + ) -> _IRQ: + """ + Configure an interrupt handler to be called when a UART event occurs. + + The arguments are: + + - *handler* is an optional function to be called when the interrupt event + triggers. The handler must take exactly one argument which is the + ``UART`` instance. + + - *trigger* configures the event(s) which can generate an interrupt. + Possible values are a mask of one or more of the following: + + - ``UART.IRQ_RXIDLE`` interrupt after receiving at least one character + and then the RX line goes idle. + - ``UART.IRQ_RX`` interrupt after each received character. + - ``UART.IRQ_TXIDLE`` interrupt after or while the last character(s) of + a message are or have been sent. + - ``UART.IRQ_BREAK`` interrupt when a break state is detected at RX + + - *hard* if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + + Returns an irq object. + + Due to limitations of the hardware not all trigger events are available on all ports. + """ + ... + def sendbreak(self) -> None: + """ + Send a break condition on the bus. This drives the bus low for a duration + longer than required for a normal transmission of a character. + """ + ... + def deinit(self) -> None: + """ + Turn off the UART bus. + + .. note:: + You will not be able to call ``init()`` on the object after ``deinit()``. + A new instance needs to be created in that case. + """ + ... + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + def flush(self) -> Incomplete: + """ + Waits until all data has been sent. In case of a timeout, an exception is raised. The timeout + duration depends on the tx buffer size and the baud rate. Unless flow control is enabled, a timeout + should not occur. + + .. note:: + + For the esp8266 and nrf ports the call returns while the last byte is sent. + If required, a one character wait time has to be added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + def txdone(self) -> bool: + """ + Tells whether all data has been sent or no data transfer is happening. In this case, + it returns ``True``. If a data transmission is ongoing it returns ``False``. + + .. note:: + + For the esp8266 and nrf ports the call may return ``True`` even if the last byte + of a transfer is still being sent. If required, a one character wait time has to be + added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read without + blocking. It will return 0 if there are no characters available and a positive + number if there are characters. The method may return 1 even if there is more + than one character available for reading. + + For more sophisticated querying of available characters use select.poll:: + + poll = select.poll() + poll.register(uart, select.POLLIN) + poll.poll(timeout) + """ + ... + def write(self, buf: AnyReadableBuf, /) -> Union[int, None]: + """ + Write the buffer of bytes to the bus. + + Return value: number of bytes written or ``None`` on timeout. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + def readline(self) -> Union[str, None]: + """ + Read a line, ending in a newline character. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: the line read or ``None`` on timeout. + """ + ... + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + +class PWM: + """ + This class provides pulse width modulation output. + + Example usage:: + + from machine import PWM + + pwm = PWM(pin) # create a PWM object on a pin + pwm.duty_u16(32768) # set duty to 50% + + # reinitialise with a period of 200us, duty of 5us + pwm.init(freq=5000, duty_ns=5000) + + pwm.duty_ns(3000) # set pulse width to 3us + + pwm.deinit() + + + Limitations of PWM + ------------------ + + * Not all frequencies can be generated with absolute accuracy due to + the discrete nature of the computing hardware. Typically the PWM frequency + is obtained by dividing some integer base frequency by an integer divider. + For example, if the base frequency is 80MHz and the required PWM frequency is + 300kHz the divider must be a non-integer number 80000000 / 300000 = 266.67. + After rounding the divider is set to 267 and the PWM frequency will be + 80000000 / 267 = 299625.5 Hz, not 300kHz. If the divider is set to 266 then + the PWM frequency will be 80000000 / 266 = 300751.9 Hz, but again not 300kHz. + + * The duty cycle has the same discrete nature and its absolute accuracy is not + achievable. On most hardware platforms the duty will be applied at the next + frequency period. Therefore, you should wait more than "1/frequency" before + measuring the duty. + + * The frequency and the duty cycle resolution are usually interdependent. + The higher the PWM frequency the lower the duty resolution which is available, + and vice versa. For example, a 300kHz PWM frequency can have a duty cycle + resolution of 8 bit, not 16-bit as may be expected. In this case, the lowest + 8 bits of *duty_u16* are insignificant. So:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2) + + and:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255) + + will generate PWM with the same 50% duty cycle. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + def init(self, *, freq: int = ..., duty_u16: int = ..., duty_ns: int = ...) -> None: + """ + Modify settings for the PWM object. See the above constructor for details + about the parameters. + """ + ... + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + def deinit(self) -> None: + """ + Disable the PWM output. + """ + ... + def __init__( + self, + dest: PinLike, + /, + *, + freq: int = ..., + duty_u16: int = ..., + duty_ns: int = ..., + ) -> None: + """ + Construct and return a new PWM object using the following parameters: + + - *dest* is the entity on which the PWM is output, which is usually a + :ref:`machine.Pin ` object, but a port may allow other values, + like integers. + - *freq* should be an integer which sets the frequency in Hz for the + PWM cycle. + - *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``. + - *duty_ns* sets the pulse width in nanoseconds. + + Setting *freq* may affect other PWM objects if the objects share the same + underlying PWM generator (this is hardware specific). + Only one of *duty_u16* and *duty_ns* should be specified at a time. + """ + +class Signal(Pin): + """ + The Signal class is a simple extension of the `Pin` class. Unlike Pin, which + can be only in "absolute" 0 and 1 states, a Signal can be in "asserted" + (on) or "deasserted" (off) states, while being inverted (active-low) or + not. In other words, it adds logical inversion support to Pin functionality. + While this may seem a simple addition, it is exactly what is needed to + support wide array of simple digital devices in a way portable across + different boards, which is one of the major MicroPython goals. Regardless + of whether different users have an active-high or active-low LED, a normally + open or normally closed relay - you can develop a single, nicely looking + application which works with each of them, and capture hardware + configuration differences in few lines in the config file of your app. + + Example:: + + from machine import Pin, Signal + + # Suppose you have an active-high LED on pin 0 + led1_pin = Pin(0, Pin.OUT) + # ... and active-low LED on pin 1 + led2_pin = Pin(1, Pin.OUT) + + # Now to light up both of them using Pin class, you'll need to set + # them to different values + led1_pin.value(1) + led2_pin.value(0) + + # Signal class allows to abstract away active-high/active-low + # difference + led1 = Signal(led1_pin, invert=False) + led2 = Signal(led2_pin, invert=True) + + # Now lighting up them looks the same + led1.value(1) + led2.value(1) + + # Even better: + led1.on() + led2.on() + + Following is the guide when Signal vs Pin should be used: + + * Use Signal: If you want to control a simple on/off (including software + PWM!) devices like LEDs, multi-segment indicators, relays, buzzers, or + read simple binary sensors, like normally open or normally closed buttons, + pulled high or low, Reed switches, moisture/flame detectors, etc. etc. + Summing up, if you have a real physical device/sensor requiring GPIO + access, you likely should use a Signal. + + * Use Pin: If you implement a higher-level protocol or bus to communicate + with more complex devices. + + The split between Pin and Signal come from the use cases above and the + architecture of MicroPython: Pin offers the lowest overhead, which may + be important when bit-banging protocols. But Signal adds additional + flexibility on top of Pin, at the cost of minor overhead (much smaller + than if you implemented active-high vs active-low device differences in + Python manually!). Also, Pin is a low-level object which needs to be + implemented for each support board, while Signal is a high-level object + which comes for free once Pin is implemented. + + If in doubt, give the Signal a try! Once again, it is offered to save + developers from the need to handle unexciting differences like active-low + vs active-high signals, and allow other users to share and enjoy your + application, instead of being frustrated by the fact that it doesn't + work for them simply because their LEDs or relays are wired in a slightly + different way. + """ + def off(self) -> None: + """ + Deactivate signal. + """ + ... + def on(self) -> None: + """ + Activate signal. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + +class Pin: + """ + A pin object is used to control I/O pins (also known as GPIO - general-purpose + input/output). Pin objects are commonly associated with a physical pin that can + drive an output voltage and read input voltages. The pin class has methods to set the mode of + the pin (IN, OUT, etc) and methods to get and set the digital logic level. + For analog control of a pin, see the :class:`ADC` class. + + A pin object is constructed by using an identifier which unambiguously + specifies a certain I/O pin. The allowed forms of the identifier and the + physical pin that the identifier maps to are port-specific. Possibilities + for the identifier are an integer, a string or a tuple with port and pin + number. + + Usage Model:: + + from machine import Pin + + # create an output pin on pin #0 + p0 = Pin(0, Pin.OUT) + + # set the value low then high + p0.value(0) + p0.value(1) + + # create an input pin on pin #2, with a pull up resistor + p2 = Pin(2, Pin.IN, Pin.PULL_UP) + + # read and print the pin value + print(p2.value()) + + # reconfigure pin #0 in input mode with a pull down resistor + p0.init(p0.IN, p0.PULL_DOWN) + + # configure an irq callback + p0.irq(lambda p:print(p)) + """ + + OPEN_DRAIN: Final[int] = 2 + """Selects the pin mode.""" + IRQ_RISING: Final[int] = 1 + """Selects the IRQ trigger type.""" + IRQ_FALLING: Final[int] = 2 + """Selects the IRQ trigger type.""" + IN: Final[int] = 0 + """Selects the pin mode.""" + PULL_UP_22K: Final[int] = 3 + OUT: Final[int] = 1 + """Selects the pin mode.""" + PULL_UP: Final[int] = 2 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_HOLD: Final[int] = 5 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_DOWN: Final[int] = 0 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + DRIVE_2: Final[int] = 3 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_1: Final[int] = 2 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_0: Final[int] = 1 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + PULL_UP_47K: Final[int] = 1 + DRIVE_OFF: Final[int] = 0 + DRIVE_3: Final[int] = 4 + DRIVE_6: Final[int] = 7 + DRIVE_5: Final[int] = 6 + DRIVE_4: Final[int] = 5 + ALT: Incomplete + ALT_OPEN_DRAIN: Incomplete + ANALOG: Incomplete + IRQ_LOW_LEVEL: Incomplete + IRQ_HIGH_LEVEL: Incomplete + def low(self) -> None: + """ + Set pin to "0" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + def irq( + self, + /, + handler: Callable[[Pin], None] | None = None, + trigger: int = (IRQ_FALLING | IRQ_RISING), + *, + priority: int = 1, + wake: int | None = None, + hard: bool = False, + ) -> Callable[..., Incomplete]: + """ + Configure an interrupt handler to be called when the trigger source of the + pin is active. If the pin mode is ``Pin.IN`` then the trigger source is + the external value on the pin. If the pin mode is ``Pin.OUT`` then the + trigger source is the output buffer of the pin. Otherwise, if the pin mode + is ``Pin.OPEN_DRAIN`` then the trigger source is the output buffer for + state '0' and the external pin value for state '1'. + + The arguments are: + + - ``handler`` is an optional function to be called when the interrupt + triggers. The handler must take exactly one argument which is the + ``Pin`` instance. + + - ``trigger`` configures the event which can generate an interrupt. + Possible values are: + + - ``Pin.IRQ_FALLING`` interrupt on falling edge. + - ``Pin.IRQ_RISING`` interrupt on rising edge. + - ``Pin.IRQ_LOW_LEVEL`` interrupt on low level. + - ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level. + + These values can be OR'ed together to trigger on multiple events. + + - ``priority`` sets the priority level of the interrupt. The values it + can take are port-specific, but higher values always represent higher + priorities. + + - ``wake`` selects the power mode in which this interrupt can wake up the + system. It can be ``machine.IDLE``, ``machine.SLEEP`` or ``machine.DEEPSLEEP``. + These values can also be OR'ed together to make a pin generate interrupts in + more than one power mode. + + - ``hard`` if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + Not all ports support this argument. + + This method returns a callback object. + + The following methods are not part of the core Pin API and only implemented on certain ports. + """ + ... + def toggle(self) -> Incomplete: + """ + Toggle output pin from "0" to "1" or vice-versa. + + Availability: cc3200, esp32, esp8266, mimxrt, rp2, samd ports. + """ + ... + def off(self) -> None: + """ + Set pin to "0" output level. + """ + ... + def on(self) -> None: + """ + Set pin to "1" output level. + """ + ... + def init( + self, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Re-initialise the pin using the given parameters. Only those arguments that + are specified will be set. The rest of the pin peripheral state will remain + unchanged. See the constructor documentation for details of the arguments. + + Returns ``None``. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + def high(self) -> None: + """ + Set pin to "1" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + + class cpu: + GPIO_SD_00: Pin ## = Pin(GPIO_SD_00) + GPIO_AD_14: Pin ## = Pin(GPIO_AD_14) + GPIO_AD_13: Pin ## = Pin(GPIO_AD_13) + GPIO_SD_01: Pin ## = Pin(GPIO_SD_01) + GPIO_SD_02: Pin ## = Pin(GPIO_SD_02) + PMIC_ON_REQ: Pin ## = Pin(PMIC_ON_REQ) + GPIO_AD_09: Pin ## = Pin(GPIO_AD_09) + GPIO_AD_08: Pin ## = Pin(GPIO_AD_08) + GPIO_AD_12: Pin ## = Pin(GPIO_AD_12) + GPIO_AD_10: Pin ## = Pin(GPIO_AD_10) + GPIO_AD_11: Pin ## = Pin(GPIO_AD_11) + GPIO_SD_11: Pin ## = Pin(GPIO_SD_11) + GPIO_SD_10: Pin ## = Pin(GPIO_SD_10) + GPIO_SD_09: Pin ## = Pin(GPIO_SD_09) + GPIO_SD_12: Pin ## = Pin(GPIO_SD_12) + GPIO_SD_13: Pin ## = Pin(GPIO_SD_13) + GPIO_SD_03: Pin ## = Pin(GPIO_SD_03) + GPIO_SD_05: Pin ## = Pin(GPIO_SD_05) + GPIO_SD_04: Pin ## = Pin(GPIO_SD_04) + GPIO_SD_08: Pin ## = Pin(GPIO_SD_08) + GPIO_SD_06: Pin ## = Pin(GPIO_SD_06) + GPIO_SD_07: Pin ## = Pin(GPIO_SD_07) + GPIO_07: Pin ## = Pin(GPIO_07) + GPIO_06: Pin ## = Pin(GPIO_06) + GPIO_05: Pin ## = Pin(GPIO_05) + GPIO_08: Pin ## = Pin(GPIO_08) + GPIO_09: Pin ## = Pin(GPIO_09) + GPIO_AD_07: Pin ## = Pin(GPIO_AD_07) + GPIO_01: Pin ## = Pin(GPIO_01) + GPIO_00: Pin ## = Pin(GPIO_00) + GPIO_04: Pin ## = Pin(GPIO_04) + GPIO_02: Pin ## = Pin(GPIO_02) + GPIO_03: Pin ## = Pin(GPIO_03) + GPIO_AD_04: Pin ## = Pin(GPIO_AD_04) + GPIO_AD_03: Pin ## = Pin(GPIO_AD_03) + GPIO_AD_02: Pin ## = Pin(GPIO_AD_02) + GPIO_AD_05: Pin ## = Pin(GPIO_AD_05) + GPIO_AD_06: Pin ## = Pin(GPIO_AD_06) + GPIO_10: Pin ## = Pin(GPIO_10) + GPIO_12: Pin ## = Pin(GPIO_12) + GPIO_11: Pin ## = Pin(GPIO_11) + GPIO_AD_01: Pin ## = Pin(GPIO_AD_01) + GPIO_13: Pin ## = Pin(GPIO_13) + GPIO_AD_00: Pin ## = Pin(GPIO_AD_00) + def __init__(self, *argv, **kwargs) -> None: ... + + class board: + LED_GREEN: Pin ## = Pin(GPIO_11) + ENC_B: Pin ## = Pin(GPIO_AD_06) + PWM_AT: Pin ## = Pin(GPIO_02) + MCK: Pin ## = Pin(GPIO_08) + PWM_AB: Pin ## = Pin(GPIO_01) + D7: Pin ## = Pin(GPIO_AD_02) + D6: Pin ## = Pin(GPIO_AD_01) + ENC_A: Pin ## = Pin(GPIO_AD_05) + D8: Pin ## = Pin(GPIO_SD_02) + D9: Pin ## = Pin(GPIO_03) + D5: Pin ## = Pin(GPIO_01) + SD_TX: Pin ## = Pin(GPIO_04) + SD_RX: Pin ## = Pin(GPIO_03) + PWM_BB: Pin ## = Pin(GPIO_03) + VOLT_DCB: Pin ## = Pin(GPIO_AD_09) + WS_RX: Pin ## = Pin(GPIO_02) + PWM_CB: Pin ## = Pin(GPIO_05) + PWM_BT: Pin ## = Pin(GPIO_04) + SCK_TX: Pin ## = Pin(GPIO_06) + PWM_CT: Pin ## = Pin(GPIO_06) + SCK_RX: Pin ## = Pin(GPIO_01) + WS_TX: Pin ## = Pin(GPIO_07) + CUR_A: Pin ## = Pin(GPIO_AD_01) + A5: Pin ## = Pin(GPIO_AD_02) + CUR_DCB: Pin ## = Pin(GPIO_AD_10) + CUR_B: Pin ## = Pin(GPIO_AD_02) + CUR_C: Pin ## = Pin(GPIO_AD_07) + A1: Pin ## = Pin(GPIO_AD_09) + A0: Pin ## = Pin(GPIO_AD_07) + A4: Pin ## = Pin(GPIO_AD_01) + A2: Pin ## = Pin(GPIO_AD_10) + A3: Pin ## = Pin(GPIO_AD_14) + D4: Pin ## = Pin(GPIO_08) + D15: Pin ## = Pin(GPIO_02) + D14: Pin ## = Pin(GPIO_01) + D0: Pin ## = Pin(GPIO_09) + D2: Pin ## = Pin(GPIO_AD_05) + D3: Pin ## = Pin(GPIO_AD_06) + D10: Pin ## = Pin(GPIO_AD_05) + D1: Pin ## = Pin(GPIO_10) + D13: Pin ## = Pin(GPIO_AD_06) + D11: Pin ## = Pin(GPIO_AD_04) + D12: Pin ## = Pin(GPIO_AD_03) + def __init__(self, *argv, **kwargs) -> None: ... + + def __init__( + self, + id: Any, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Access the pin peripheral (GPIO pin) associated with the given ``id``. If + additional arguments are given in the constructor then they are used to initialise + the pin. Any settings that are not specified will remain in their previous state. + + The arguments are: + + - ``id`` is mandatory and can be an arbitrary object. Among possible value + types are: int (an internal Pin identifier), str (a Pin name), and tuple + (pair of [port, pin]). + + - ``mode`` specifies the pin mode, which can be one of: + + - ``Pin.IN`` - Pin is configured for input. If viewed as an output the pin + is in high-impedance state. + + - ``Pin.OUT`` - Pin is configured for (normal) output. + + - ``Pin.OPEN_DRAIN`` - Pin is configured for open-drain output. Open-drain + output works in the following way: if the output value is set to 0 the pin + is active at a low level; if the output value is 1 the pin is in a high-impedance + state. Not all ports implement this mode, or some might only on certain pins. + + - ``Pin.ALT`` - Pin is configured to perform an alternative function, which is + port specific. For a pin configured in such a way any other Pin methods + (except :meth:`Pin.init`) are not applicable (calling them will lead to undefined, + or a hardware-specific, result). Not all ports implement this mode. + + - ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as + open-drain. Not all ports implement this mode. + + - ``Pin.ANALOG`` - Pin is configured for analog input, see the :class:`ADC` class. + + - ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be + one of: + + - ``None`` - No pull up or down resistor. + - ``Pin.PULL_UP`` - Pull up resistor enabled. + - ``Pin.PULL_DOWN`` - Pull down resistor enabled. + + - ``value`` is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and specifies initial + output pin value if given, otherwise the state of the pin peripheral remains + unchanged. + + - ``drive`` specifies the output power of the pin and can be one of: ``Pin.LOW_POWER``, + ``Pin.MED_POWER`` or ``Pin.HIGH_POWER``. The actual current driving capabilities + are port dependent. Not all ports implement this argument. + + - ``alt`` specifies an alternate function for the pin and the values it can take are + port dependent. This argument is valid only for ``Pin.ALT`` and ``Pin.ALT_OPEN_DRAIN`` + modes. It may be used when a pin supports more than one alternate function. If only + one pin alternate function is supported the this argument is not required. Not all + ports implement this argument. + + As specified above, the Pin class allows to set an alternate function for a particular + pin, but it does not specify any further operations on such a pin. Pins configured in + alternate-function mode are usually not used as GPIO but are instead driven by other + hardware peripherals. The only operation supported on such a pin is re-initialising, + by calling the constructor or :meth:`Pin.init` method. If a pin that is configured in + alternate-function mode is re-initialised with ``Pin.IN``, ``Pin.OUT``, or + ``Pin.OPEN_DRAIN``, the alternate function will be removed from the pin. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class RTC: + """ + The RTC is an independent clock that keeps track of the date + and time. + + Example usage:: + + rtc = machine.RTC() + rtc.datetime((2020, 1, 21, 2, 10, 32, 36, 0)) + print(rtc.datetime()) + + + + The documentation for RTC is in a poor state;1 + """ + + ALARM0: Final[int] = 0 + """irq trigger source""" + def irq( + self, + /, + *, + trigger: int, + handler: Callable[[RTC], None] | None = None, + wake: int = IDLE, + ) -> None: + """ + Create an irq object triggered by a real time clock alarm. + + - ``trigger`` must be ``RTC.ALARM0`` + - ``handler`` is the function to be called when the callback is triggered. + - ``wake`` specifies the sleep mode from where this interrupt can wake + up the system. + """ + ... + def cancel(self, *args, **kwargs) -> Incomplete: ... + def datetime(self, datetimetuple: Any | None = None) -> Tuple: + """ + Get or set the date and time of the RTC. + + With no arguments, this method returns an 8-tuple with the current + date and time. With 1 argument (being an 8-tuple) it sets the date + and time. + + The 8-tuple has the following format: + + (year, month, day, weekday, hours, minutes, seconds, subseconds) + + The meaning of the ``subseconds`` field is hardware dependent. + """ + ... + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + def calibration(self, *args, **kwargs) -> Incomplete: ... + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + def alarm_cancel(self, alarm_id: int = 0, /) -> None: + """ + Cancel a running alarm. + + The mimxrt port also exposes this function as ``RTC.cancel(alarm_id=0)``, but this is + scheduled to be removed in MicroPython 2.0. + """ + ... + def alarm_left(self, alarm_id: int = 0, /) -> int: + """ + Get the number of milliseconds left before the alarm expires. + """ + ... + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + +class SPI: + """ + SPI is a synchronous serial protocol that is driven by a controller. At the + physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices + can share the same bus. Each device should have a separate, 4th signal, + CS (Chip Select), to select a particular device on a bus with which + communication takes place. Management of a CS signal should happen in + user code (via machine.Pin class). + + Both hardware and software SPI implementations exist via the + :ref:`machine.SPI ` and `machine.SoftSPI` classes. Hardware SPI uses underlying + hardware support of the system to perform the reads/writes and is usually + efficient and fast but may have restrictions on which pins can be used. + Software SPI is implemented by bit-banging and can be used on any pin but + is not as efficient. These classes have the same methods available and + differ primarily in the way they are constructed. + + Example usage:: + + from machine import SPI, Pin + + spi = SPI(0, baudrate=400000) # Create SPI peripheral 0 at frequency of 400kHz. + # Depending on the use case, extra parameters may be required + # to select the bus characteristics and/or pins to use. + cs = Pin(4, mode=Pin.OUT, value=1) # Create chip-select on pin 4. + + try: + cs(0) # Select peripheral. + spi.write(b"12345678") # Write 8 bytes, and don't care about received data. + finally: + cs(1) # Deselect peripheral. + + try: + cs(0) # Select peripheral. + rxdata = spi.read(8, 0x42) # Read 8 bytes while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + rxdata = bytearray(8) + try: + cs(0) # Select peripheral. + spi.readinto(rxdata, 0x42) # Read 8 bytes inplace while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + txdata = b"12345678" + rxdata = bytearray(len(txdata)) + try: + cs(0) # Select peripheral. + spi.write_readinto(txdata, rxdata) # Simultaneously write and read bytes. + finally: + cs(1) # Deselect peripheral. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + CONTROLLER: Incomplete + def deinit(self) -> None: + """ + Turn off the SPI bus. + """ + ... + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + def write_readinto(self, write_buf: AnyReadableBuf, read_buf: AnyWritableBuf, /) -> int: + """ + Write the bytes from ``write_buf`` while reading into ``read_buf``. The + buffers can be the same or different, but both buffers must have the + same length. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def read(self, nbytes: int, write: int = 0x00, /) -> bytes: + """ + Read a number of bytes specified by ``nbytes`` while continuously writing + the single byte given by ``write``. + Returns a ``bytes`` object with the data that was read. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes contained in ``buf``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def readinto(self, buf: AnyWritableBuf, write: int = 0x00, /) -> int: + """ + Read into the buffer specified by ``buf`` while continuously writing the + single byte given by ``write``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes read. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/math.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/math.pyi new file mode 100644 index 000000000..606eb1389 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/math.pyi @@ -0,0 +1,269 @@ +""" +Mathematical functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/math.html + +CPython module: :mod:`python:math` https://docs.python.org/3/library/math.html . + +The ``math`` module provides some basic mathematical functions for +working with floating-point numbers. + +*Note:* On the pyboard, floating-point numbers have 32-bit precision. + +Availability: not available on WiPy. Floating point support required +for this module. + +--- +Module: 'math' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsFloat, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +inf: float = inf +nan: float = nan +pi: float = 3.1415928 +"""the ratio of a circle's circumference to its diameter""" +e: float = 2.7182818 +"""base of the natural logarithm""" +tau: float = 6.2831856 + +def ldexp(x: SupportsFloat, exp: int, /) -> float: + """ + Return ``x * (2**exp)``. + """ + ... + +def lgamma(x: SupportsFloat, /) -> float: + """ + Return the natural logarithm of the gamma function of ``x``. + """ + ... + +def trunc(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards 0. + """ + ... + +def isclose(*args, **kwargs) -> Incomplete: ... +def gamma(x: SupportsFloat, /) -> float: + """ + Return the gamma function of ``x``. + """ + ... + +def isnan(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is not-a-number + """ + ... + +def isfinite(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is finite. + """ + ... + +def isinf(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is infinite. + """ + ... + +def sqrt(x: SupportsFloat, /) -> float: + """ + Return the square root of ``x``. + """ + ... + +def sinh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic sine of ``x``. + """ + ... + +def log(x: SupportsFloat, /) -> float: + """ + With one argument, return the natural logarithm of *x*. + + With two arguments, return the logarithm of *x* to the given *base*. + """ + ... + +def tan(x: SupportsFloat, /) -> float: + """ + Return the tangent of ``x``. + """ + ... + +def tanh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic tangent of ``x``. + """ + ... + +def log2(x: SupportsFloat, /) -> float: + """ + Return the base-2 logarithm of ``x``. + """ + ... + +def log10(x: SupportsFloat, /) -> float: + """ + Return the base-10 logarithm of ``x``. + """ + ... + +def sin(x: SupportsFloat, /) -> float: + """ + Return the sine of ``x``. + """ + ... + +def modf(x: SupportsFloat, /) -> Tuple: + """ + Return a tuple of two floats, being the fractional and integral parts of + ``x``. Both return values have the same sign as ``x``. + """ + ... + +def radians(x: SupportsFloat, /) -> float: + """ + Return degrees ``x`` converted to radians. + """ + ... + +def atanh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic tangent of ``x``. + """ + ... + +def atan2(y: SupportsFloat, x: SupportsFloat, /) -> float: + """ + Return the principal value of the inverse tangent of ``y/x``. + """ + ... + +def atan(x: SupportsFloat, /) -> float: + """ + Return the inverse tangent of ``x``. + """ + ... + +def ceil(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards positive infinity. + """ + ... + +def copysign(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return ``x`` with the sign of ``y``. + """ + ... + +def frexp(x: SupportsFloat, /) -> tuple[float, 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 acos(x: SupportsFloat, /) -> float: + """ + Return the inverse cosine of ``x``. + """ + ... + +def pow(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Returns ``x`` to the power of ``y``. + """ + ... + +def asinh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic sine of ``x``. + """ + ... + +def acosh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic cosine of ``x``. + """ + ... + +def asin(x: SupportsFloat, /) -> float: + """ + Return the inverse sine of ``x``. + """ + ... + +def factorial(*args, **kwargs) -> Incomplete: ... +def fabs(x: SupportsFloat, /) -> float: + """ + Return the absolute value of ``x``. + """ + ... + +def expm1(x: SupportsFloat, /) -> float: + """ + Return ``exp(x) - 1``. + """ + ... + +def floor(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards negative infinity. + """ + ... + +def fmod(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return the remainder of ``x/y``. + """ + ... + +def cos(x: SupportsFloat, /) -> float: + """ + Return the cosine of ``x``. + """ + ... + +def degrees(x: SupportsFloat, /) -> float: + """ + Return radians ``x`` converted to degrees. + """ + ... + +def cosh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic cosine of ``x``. + """ + ... + +def exp(x: SupportsFloat, /) -> float: + """ + Return the exponential of ``x``. + """ + ... + +def erf(x: SupportsFloat, /) -> float: + """ + Return the error function of ``x``. + """ + ... + +def erfc(x: SupportsFloat, /) -> float: + """ + Return the complementary error function of ``x``. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/micropython.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/micropython.pyi new file mode 100644 index 000000000..527d48e8c --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/micropython.pyi @@ -0,0 +1,346 @@ +""" +Access and control MicroPython internals. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/micropython.html + +--- +Module: 'micropython' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Any, Callable, Optional, Tuple, overload +from typing_extensions import Awaitable, ParamSpec, TypeAlias, TypeVar + +_T = TypeVar("_T") +_F = TypeVar("_F", bound=Callable[..., Any]) +Const_T = TypeVar("Const_T", int, float, str, bytes, Tuple) +_Param = ParamSpec("_Param") +_Ret = TypeVar("_Ret") + +@overload +def opt_level() -> int: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def opt_level(level: int, /) -> None: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def mem_info() -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +@overload +def mem_info(verbose: Any, /) -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +def kbd_intr(chr: int) -> None: + """ + Set the character that will raise a `KeyboardInterrupt` exception. By + default this is set to 3 during script execution, corresponding to Ctrl-C. + Passing -1 to this function will disable capture of Ctrl-C, and passing 3 + will restore it. + + This function can be used to prevent the capturing of Ctrl-C on the + incoming stream of characters that is usually used for the REPL, in case + that stream is used for other purposes. + """ + ... + +@overload +def qstr_info() -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +@overload +def qstr_info(verbose: bool, /) -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +def schedule(func: Callable[[_T], None], arg: _T, /) -> None: + """ + Schedule the function *func* to be executed "very soon". The function + is passed the value *arg* as its single argument. "Very soon" means that + the MicroPython runtime will do its best to execute the function at the + earliest possible time, given that it is also trying to be efficient, and + that the following conditions hold: + + - A scheduled function will never preempt another scheduled function. + - Scheduled functions are always executed "between opcodes" which means + that all fundamental Python operations (such as appending to a list) + are guaranteed to be atomic. + - A given port may define "critical regions" within which scheduled + functions will never be executed. Functions may be scheduled within + a critical region but they will not be executed until that region + is exited. An example of a critical region is a preempting interrupt + handler (an IRQ). + + A use for this function is to schedule a callback from a preempting IRQ. + Such an IRQ puts restrictions on the code that runs in the IRQ (for example + the heap may be locked) and scheduling a function to call later will lift + those restrictions. + + On multi-threaded ports, the scheduled function's behaviour depends on + whether the Global Interpreter Lock (GIL) is enabled for the specific port: + + - If GIL is enabled, the function can preempt any thread and run in its + context. + - If GIL is disabled, the function will only preempt the main thread and run + in its context. + + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite queue to hold the scheduled functions and `schedule()` + will raise a `RuntimeError` if the queue is full. + """ + ... + +def stack_use() -> int: + """ + Return an integer representing the current amount of stack that is being + used. The absolute value of this is not particularly useful, rather it + should be used to compute differences in stack usage at different points. + """ + ... + +def heap_unlock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def const(expr: Const_T, /) -> Const_T: + """ + Used to declare that the expression is a constant so that the compiler can + optimise it. The use of this function should be as follows:: + + from micropython import const + + CONST_X = const(123) + CONST_Y = const(2 * CONST_X + 1) + + Constants declared this way are still accessible as global variables from + outside the module they are declared in. On the other hand, if a constant + begins with an underscore then it is hidden, it is not available as a global + variable, and does not take up any memory during execution. + + This `const` function is recognised directly by the MicroPython parser and is + provided as part of the :mod:`micropython` module mainly so that scripts can be + written which run under both CPython and MicroPython, by following the above + pattern. + """ + ... + +def heap_lock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def alloc_emergency_exception_buf(size: int, /) -> None: + """ + Allocate *size* bytes of RAM for the emergency exception buffer (a good + size is around 100 bytes). The buffer is used to create exceptions in cases + when normal RAM allocation would fail (eg within an interrupt handler) and + therefore give useful traceback information in these situations. + + A good way to use this function is to put it at the start of your main script + (eg ``boot.py`` or ``main.py``) and then the emergency exception buffer will be active + for all the code following it. + """ + ... + +class RingIO: + def readinto(self, buf, nbytes: Optional[Any] = None) -> int: + """ + Read available bytes into the provided ``buf``. If ``nbytes`` is + specified then read at most that many bytes. Otherwise, read at + most ``len(buf)`` bytes. + + Return value: Integer count of the number of bytes read into ``buf``. + """ + ... + def write(self, buf) -> int: + """ + Non-blocking write of bytes from ``buf`` into the ringbuffer, limited + by the available space in the ringbuffer. + + Return value: Integer count of bytes written. + """ + ... + def readline(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read a line, ending in a newline character or return if one exists in + the buffer, else return available bytes in buffer. If ``nbytes`` is + specified then read at most that many bytes. + + Return value: a bytes object containing the line read. + """ + ... + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read. + """ + ... + def read(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read available characters. This is a non-blocking function. If ``nbytes`` + is specified then read at most that many bytes, otherwise read as much + data as possible. + + Return value: a bytes object containing the bytes read. Will be + zero-length bytes object if no data is available. + """ + ... + def close(self) -> Incomplete: + """ + No-op provided as part of standard `stream` interface. Has no effect + on data in the ringbuffer. + """ + ... + def __init__(self, size) -> None: ... + +# decorators +@mp_available() # force merge +def viper(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + The Viper code emitter is not fully compliant. It supports special Viper native data types in pursuit of performance. + Integer processing is non-compliant because it uses machine words: arithmetic on 32 bit hardware is performed modulo 2**32. + Like the Native emitter Viper produces machine instructions but further optimisations are performed, substantially increasing + performance especially for integer arithmetic and bit manipulations. + See: https://docs.micropython.org/en/latest/reference/speed_python.html?highlight=viper#the-native-code-emitter + """ + ... + +@mp_available() # force merge +def native(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This causes the MicroPython compiler to emit native CPU opcodes rather than bytecode. + It covers the bulk of the MicroPython functionality, so most functions will require no adaptation. + See: https://docs.micropython.org/en/latest/reference/speed_python.html#the-native-code-emitter + """ + ... + +@mp_available(macro="MICROPY_EMIT_INLINE_THUMB") # force merge +def asm_thumb(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code. + The assembler code is written is a subset of the ARM Thumb-2 instruction set, and is executed on the target CPU. + + Availability: Only on specific boards where MICROPY_EMIT_INLINE_THUMB is defined. + See: https://docs.micropython.org/en/latest/reference/asm_thumb2_index.html + """ + ... + +@mp_available(port="esp8266") # force merge +def asm_xtensa(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code for the esp8266. + The assembler code is written in the Xtensa instruction set, and is executed on the target CPU. + + Availability: Only on eps8266 boards. + """ + ... + # See : + # - https://github.com/orgs/micropython/discussions/12965 + # - https://github.com/micropython/micropython/pull/16731 diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/mimxrt.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/mimxrt.pyi new file mode 100644 index 000000000..27ed8e301 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/mimxrt.pyi @@ -0,0 +1,14 @@ +""" +Module: 'mimxrt' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class Flash: + def readblocks(self, *args, **kwargs) -> Incomplete: ... + def writeblocks(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/network.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/network.pyi new file mode 100644 index 000000000..e6651185a --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/network.pyi @@ -0,0 +1,386 @@ +""" +Network configuration. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/network.html + +This module provides network drivers and routing configuration. To use this +module, a MicroPython variant/build with network capabilities must be installed. +Network drivers for specific hardware are available within this module and are +used to configure hardware network interface(s). Network services provided +by configured interfaces are then available for use via the :mod:`socket` +module. + +For example:: + + # connect/ show IP config a specific network interface + # see below for examples of specific drivers + import network + import time + nic = network.Driver(...) + if not nic.isconnected(): + nic.connect() + print("Waiting for connection...") + while not nic.isconnected(): + time.sleep(1) + print(nic.ipconfig("addr4")) + + # now use socket as usual + import socket + addr = socket.getaddrinfo('micropython.org', 80)[0][-1] + s = socket.socket() + s.connect(addr) + s.send(b'GET / HTTP/1.1 +Host: micropython.org + +') + data = s.recv(1000) + s.close() + +--- +Module: 'network' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Protocol, Callable, overload, Any, List, Optional, Tuple, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar +from machine import Pin, SPI +from abc import abstractmethod + +STA_IF: Final[int] = 0 +AP_IF: Final[int] = 1 + +def hostname(name: Optional[Any] = None) -> Incomplete: + """ + Get or set the hostname that will identify this device on the network. It will + be used by all interfaces. + + This hostname is used for: + * Sending to the DHCP server in the client request. (If using DHCP) + * Broadcasting via mDNS. (If enabled) + + If the *name* parameter is provided, the hostname will be set to this value. + If the function is called without parameters, it returns the current + hostname. + + A change in hostname is typically only applied during connection. For DHCP + this is because the hostname is part of the DHCP client request, and the + implementation of mDNS in most ports only initialises the hostname once + during connection. For this reason, you must set the hostname before + activating/connecting your network interfaces. + + The length of the hostname is limited to 32 characters. + :term:`MicroPython ports ` may choose to set a lower + limit for memory reasons. If the given name does not fit, a `ValueError` + is raised. + + The default hostname is typically the name of the board. + """ + ... + +def route(*args, **kwargs) -> Incomplete: ... +def country(code: Optional[Any] = None) -> Incomplete: + """ + Get or set the two-letter ISO 3166-1 Alpha-2 country code to be used for + radio compliance. + + If the *code* parameter is provided, the country will be set to this value. + If the function is called without parameters, it returns the current + country. + + The default code ``"XX"`` represents the "worldwide" region. + """ + ... + +class WLANWiPy: + @overload + def __init__(self, id: int = 0, /): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int, + ssid: str, + auth: tuple[str, str], + channel: int, + antenna: int, + ): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def mode(self) -> int: + """ + Get or set the WLAN mode. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the WLAN mode. + """ + + @overload + def ssid(self) -> str: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def ssid(self, ssid: str, /) -> None: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def auth(self) -> int: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def auth(self, auth: int, /) -> None: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def channel(self) -> int: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def channel(self, channel: int, /) -> None: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def antenna(self) -> int: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def antenna(self, antenna: int, /) -> None: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def mac(self) -> bytes: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + + @overload + def mac(self, mac: bytes, /) -> None: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + +class AbstractNIC: + @overload + @abstractmethod + def active(self, /) -> bool: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def active(self, is_active: bool | int, /) -> None: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def connect(self, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def connect(self, service_id: Any, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def status(self) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def status(self, param: str, /) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def ifconfig(self) -> tuple[str, str, str, str]: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def ifconfig(self, ip_mask_gateway_dns: tuple[str, str, str, str], /) -> None: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def config(self, param: str, /) -> Any: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ + + @overload + @abstractmethod + def config(self, **kwargs: Any) -> None: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ + +class LAN: + @overload + def active(self, /) -> bool: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ + + @overload + def active(self, is_active: bool | int, /) -> None: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/onewire.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/onewire.pyi new file mode 100644 index 000000000..0f342b252 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/onewire.pyi @@ -0,0 +1,28 @@ +""" +Module: 'onewire' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SKIP_ROM: Final[int] = 204 + SEARCH_ROM: Final[int] = 240 + MATCH_ROM: Final[int] = 85 + def select_rom(self, *args, **kwargs) -> Incomplete: ... + def writebit(self, *args, **kwargs) -> Incomplete: ... + def writebyte(self, *args, **kwargs) -> Incomplete: ... + def _search_rom(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def crc8(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def reset(self, *args, **kwargs) -> Incomplete: ... + def readbit(self, *args, **kwargs) -> Incomplete: ... + def readbyte(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/platform.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/platform.pyi new file mode 100644 index 000000000..cc7c88d22 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/platform.pyi @@ -0,0 +1,51 @@ +""" +Access to underlying platform’s identifying data. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/platform.html + +CPython module: :mod:`python:platform` https://docs.python.org/3/library/platform.html . + +This module tries to retrieve as much platform-identifying data as possible. It +makes this information available via function APIs. + +--- +Module: 'platform' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def platform() -> str: + """ + Returns a string identifying the underlying platform. This string is composed + of several substrings in the following order, delimited by dashes (``-``): + + - the name of the platform system (e.g. Unix, Windows or MicroPython) + - the MicroPython version + - the architecture of the platform + - the version of the underlying platform + - the concatenation of the name of the libc that MicroPython is linked to + and its corresponding version. + + For example, this could be + ``"MicroPython-1.20.0-xtensa-IDFv4.2.4-with-newlib3.0.0"``. + """ + ... + +def python_compiler() -> str: + """ + Returns a string identifying the compiler used for compiling MicroPython. + """ + ... + +def libc_ver() -> Tuple: + """ + Returns a tuple of strings *(lib, version)*, where *lib* is the name of the + libc that MicroPython is linked to, and *version* the corresponding version + of this libc. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/random.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/random.pyi new file mode 100644 index 000000000..bb5167074 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/random.pyi @@ -0,0 +1,115 @@ +""" +Random numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/random.html + +This module implements a pseudo-random number generator (PRNG). + +CPython module: :mod:`python:random` https://docs.python.org/3/library/random.html . . + +.. note:: + + The following notation is used for intervals: + + - () are open interval brackets and do not include their endpoints. + For example, (0, 1) means greater than 0 and less than 1. + In set notation: (0, 1) = {x | 0 < x < 1}. + + - [] are closed interval brackets which include all their limit points. + For example, [0, 1] means greater than or equal to 0 and less than + or equal to 1. + In set notation: [0, 1] = {x | 0 <= x <= 1}. + +.. note:: + + The :func:`randrange`, :func:`randint` and :func:`choice` functions are only + available if the ``MICROPY_PY_RANDOM_EXTRA_FUNCS`` configuration option is + enabled. + +--- +Module: 'random' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import Subscriptable +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +@overload +def randrange(stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, step: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +def random() -> int: + """ + Return a random floating point number in the range [0.0, 1.0). + """ + ... + +def seed(n: int | None = None, /) -> None: + """ + Initialise the random number generator module with the seed *n* which should + be an integer. When no argument (or ``None``) is passed in it will (if + supported by the port) initialise the PRNG with a true random number + (usually a hardware generated random number). + + The ``None`` case only works if ``MICROPY_PY_RANDOM_SEED_INIT_FUNC`` is + enabled by the port, otherwise it raises ``ValueError``. + """ + ... + +def uniform(a: float, b: float) -> int: + """ + Return a random floating point number N such that *a* <= N <= *b* for *a* <= *b*, + and *b* <= N <= *a* for *b* < *a*. + """ + ... + +def choice(sequence: Subscriptable, /) -> None: + """ + Chooses and returns one item at random from *sequence* (tuple, list or + any object that supports the subscript operation). + """ + ... + +def randint(a: int, b: int, /) -> int: + """ + Return a random integer in the range [*a*, *b*]. + """ + ... + +def getrandbits(n: int, /) -> int: + """ + Return an integer with *n* random bits (0 <= n <= 32). + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/select.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/select.pyi new file mode 100644 index 000000000..b2a5aa0e8 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/select.pyi @@ -0,0 +1,118 @@ +""" +Wait for events on a set of streams. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/select.html + +CPython module: :mod:`python:select` https://docs.python.org/3/library/select.html . + +This module provides functions to efficiently wait for events on multiple +`streams ` (select streams which are ready for operations). + +--- +Module: 'select' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Iterable, Iterator, List, Optional, Tuple, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +POLLOUT: Final[int] = 4 +POLLIN: Final[int] = 1 +POLLHUP: Final[int] = 16 +POLLERR: Final[int] = 8 + +def select( + rlist: Iterable[Any], + wlist: Iterable[Any], + xlist: Iterable[Any], + timeout: int = -1, + /, +) -> None: + """ + Wait for activity on a set of objects. + + This function is provided by some MicroPython ports for compatibility + and is not efficient. Usage of :class:`Poll` is recommended instead. + """ + ... + +class poll: + """ + Create an instance of the Poll class. + """ + def __init__(self) -> None: ... + def register(self, obj, eventmask: Optional[Any] = None) -> None: + """ + Register `stream` *obj* for polling. *eventmask* is logical OR of: + + * ``select.POLLIN`` - data available for reading + * ``select.POLLOUT`` - more data can be written + + Note that flags like ``select.POLLHUP`` and ``select.POLLERR`` are + *not* valid as input eventmask (these are unsolicited events which + will be returned from `poll()` regardless of whether they are asked + for). This semantics is per POSIX. + + *eventmask* defaults to ``select.POLLIN | select.POLLOUT``. + + It is OK to call this function multiple times for the same *obj*. + Successive calls will update *obj*'s eventmask to the value of + *eventmask* (i.e. will behave as `modify()`). + """ + ... + def unregister(self, obj) -> Incomplete: + """ + Unregister *obj* from polling. + """ + ... + def modify(self, obj, eventmask) -> None: + """ + Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError` + is raised with error of ENOENT. + """ + ... + def poll(self, timeout=-1, /) -> List: + """ + Wait for at least one of the registered objects to become ready or have an + exceptional condition, with optional timeout in milliseconds (if *timeout* + arg is not specified or -1, there is no timeout). + + Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in + tuple, depending on a platform and version, so don't assume that its size is 2. + The ``event`` element specifies which events happened with a stream and + is a combination of ``select.POLL*`` constants described above. Note that + flags ``select.POLLHUP`` and ``select.POLLERR`` can be returned at any time + (even if were not asked for), and must be acted on accordingly (the + corresponding stream unregistered from poll and likely closed), because + otherwise all further invocations of `poll()` may return immediately with + these flags set for this stream again. + + In case of timeout, an empty list is returned. + + Admonition:Difference to CPython + :class: attention + + Tuples returned may contain more than 2 elements as described above. + """ + ... + def ipoll(self, timeout=-1, flags=0, /) -> Iterator[Tuple]: + """ + Like :meth:`poll.poll`, but instead returns an iterator which yields a + `callee-owned tuple`. This function provides an efficient, allocation-free + way to poll on streams. + + If *flags* is 1, one-shot behaviour for events is employed: streams for + which events happened will have their event masks automatically reset + (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream + won't be processed until new mask is set with `poll.modify()`. This + behaviour is useful for asynchronous I/O schedulers. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/socket.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/socket.pyi new file mode 100644 index 000000000..c639ed769 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/socket.pyi @@ -0,0 +1,419 @@ +""" +Socket module. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/socket.html + +CPython module: :mod:`python:socket` https://docs.python.org/3/library/socket.html . + +This module provides access to the BSD socket interface. + +Admonition:Difference to CPython + :class: attention + + For efficiency and consistency, socket objects in MicroPython implement a `stream` + (file-like) interface directly. In CPython, you need to convert a socket to + a file-like object using `makefile()` method. This method is still supported + by MicroPython (but is a no-op), so where compatibility with CPython matters, + be sure to use it. + +Socket address format(s) +------------------------ + +The native socket address format of the ``socket`` module is an opaque data type +returned by `getaddrinfo` function, which must be used to resolve textual address +(including numeric addresses):: + + sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1] + # You must use getaddrinfo() even for numeric addresses + sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1] + # Now you can use that address + sock.connect(sockaddr) + +Using `getaddrinfo` is the most efficient (both in terms of memory and processing +power) and portable way to work with addresses. + +However, ``socket`` module (note the difference with native MicroPython +``socket`` module described here) provides CPython-compatible way to specify +addresses using tuples, as described below. Note that depending on a +:term:`MicroPython port`, ``socket`` module can be builtin or need to be +installed from `micropython-lib` (as in the case of :term:`MicroPython Unix port`), +and some ports still accept only numeric addresses in the tuple format, +and require to use `getaddrinfo` function to resolve domain names. + +Summing up: + +* Always use `getaddrinfo` when writing portable applications. +* Tuple addresses described below can be used as a shortcut for + quick hacks and interactive use, if your port supports them. + +Tuple address format for ``socket`` module: + +* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with + dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and + integer port number in the range 1-65535. Note the domain names are not + accepted as *ipv4_address*, they should be resolved first using + `socket.getaddrinfo()`. +* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address* + is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``, + and *port* is an integer port number in the range 1-65535. *flowinfo* + must be 0. *scopeid* is the interface scope identifier for link-local + addresses. Note the domain names are not accepted as *ipv6_address*, + they should be resolved first using `socket.getaddrinfo()`. Availability + of IPv6 support depends on a :term:`MicroPython port`. + +--- +Module: 'socket' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Literal, Tuple, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +SO_KEEPALIVE: Final[int] = 8 +SO_BROADCAST: Final[int] = 32 +SOL_SOCKET: Final[int] = 4095 +SO_RCVTIMEO: Final[int] = 4102 +SO_REUSEADDR: Final[int] = 4 +SO_SNDTIMEO: Final[int] = 4101 +AF_INET6: Final[int] = 10 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +AF_INET: Final[int] = 2 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +SOCK_STREAM: Final[int] = 1 +"""Socket types.""" +SOCK_DGRAM: Final[int] = 2 +"""Socket types.""" +SOCK_RAW: Final[int] = 3 +IPPROTO_UDP: Incomplete +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IPPROTO_TCP: Incomplete +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IPPROTO_SEC: Incomplete +"""Special protocol value to create SSL-compatible socket.""" +_Address: TypeAlias = tuple[str, int] | tuple[str, int, int, int] | str +Socket: TypeAlias = socket + +def getaddrinfo( + host: str, + port: int, + af: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, + /, +) -> list[tuple[int, int, int, str, tuple[str, int] | tuple[str, int, int, int]]]: + """ + Translate the host/port argument into a sequence of 5-tuples that contain all the + necessary arguments for creating a socket connected to that service. Arguments + *af*, *type*, and *proto* (which have the same meaning as for the `socket()` function) + can be used to filter which kind of addresses are returned. If a parameter is not + specified or zero, all combinations of addresses can be returned (requiring + filtering on the user side). + + The resulting list of 5-tuples has the following structure:: + + (family, type, proto, canonname, sockaddr) + + The following example shows how to connect to a given url:: + + s = socket.socket() + # This assumes that if "type" is not specified, an address for + # SOCK_STREAM will be returned, which may be not true + s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1]) + + Recommended use of filtering params:: + + s = socket.socket() + # Guaranteed to return an address which can be connect'ed to for + # stream operation. + s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1]) + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.gaierror`` exception (`OSError` subclass) in case + of error in this function. MicroPython doesn't have ``socket.gaierror`` + and raises OSError directly. Note that error numbers of `getaddrinfo()` + form a separate namespace and may not match error numbers from + the :mod:`errno` module. To distinguish `getaddrinfo()` errors, they are + represented by negative numbers, whereas standard system errors are + positive numbers (error numbers are accessible using ``e.args[0]`` property + from an exception object). The use of negative values is a provisional + detail which may change in the future. + """ + ... + +class socket: + """ + A unix like socket, for more information see module ``socket``'s description. + + The name, `Socket`, used for typing is not the same as the runtime name, `socket` (note lowercase `s`). + The reason for this difference is that the runtime uses `socket` as both a class name and as a method name and + this is not possible within code written entirely in Python and therefore not possible within typing code. + """ + def recvfrom(self, bufsize: int, /) -> Tuple: + """ + Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a + bytes object representing the data received and *address* is the address of the socket sending + the data. + + See the `recv` function for an explanation of the optional *flags* argument. + """ + ... + def recv(self, bufsize: int, /) -> bytes: + """ + Receive data from the socket. The return value is a bytes object representing the data + received. The maximum amount of data to be received at once is specified by bufsize. + + Most ports support the optional *flags* argument. Available *flags* are defined as constants + in the socket module and have the same meaning as in CPython. ``MSG_PEEK`` and ``MSG_DONTWAIT`` + are supported on all ports which accept the *flags* argument. + """ + ... + + @overload + def makefile(self, mode: Literal["rb", "wb", "rwb"] = "rb", buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + + @overload + def makefile(self, mode: str, buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + def listen(self, backlog: int = ..., /) -> None: + """ + Enable a server to accept connections. If *backlog* is specified, it must be at least 0 + (if it's lower, it will be set to 0); and specifies the number of unaccepted connections + that the system will allow before refusing new connections. If not specified, a default + reasonable value is chosen. + """ + ... + def settimeout(self, value: float | None, /) -> None: + """ + **Note**: Not every port supports this method, see below. + + Set a timeout on blocking socket operations. The value argument can be a nonnegative floating + point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations + will raise an `OSError` exception if the timeout period value has elapsed before the operation has + completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket + is put in blocking mode. + + Not every :term:`MicroPython port` supports this method. A more portable and + generic solution is to use `select.poll` object. This allows to wait on + multiple objects at the same time (and not just on sockets, but on generic + `stream` objects which support polling). Example:: + + # Instead of: + s.settimeout(1.0) # time in seconds + s.read(10) # may timeout + + # Use: + poller = select.poll() + poller.register(s, select.POLLIN) + res = poller.poll(1000) # time in milliseconds + if not res: + # s is still not ready for input, i.e. operation timed out + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.timeout`` exception in case of timeout, + which is an `OSError` subclass. MicroPython raises an OSError directly + instead. If you use ``except OSError:`` to catch the exception, + your code will work both in MicroPython and CPython. + """ + ... + def sendall(self, bytes: AnyReadableBuf, /) -> int: + """ + Send all data to the socket. The socket must be connected to a remote socket. + Unlike `send()`, this method will try to send all of data, by sending data + chunk by chunk consecutively. + + The behaviour of this method on non-blocking sockets is undefined. Due to this, + on MicroPython, it's recommended to use `write()` method instead, which + has the same "no short writes" policy for blocking sockets, and will return + number of bytes sent on non-blocking sockets. + """ + ... + def setsockopt(self, level: int, optname: int, value: AnyReadableBuf | int, /) -> None: + """ + Set the value of the given socket option. The needed symbolic constants are defined in the + socket module (SO_* etc.). The *value* can be an integer or a bytes-like object representing + a buffer. + """ + ... + def setblocking(self, value: bool, /) -> None: + """ + Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking, + else to blocking mode. + + This method is a shorthand for certain `settimeout()` calls: + + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)`` + """ + ... + def sendto(self, bytes: AnyReadableBuf, address: _Address, /) -> None: + """ + Send data to the socket. The socket should not be connected to a remote socket, since the + destination socket is specified by *address*. + """ + ... + def readline(self) -> bytes: + """ + Read a line, ending in a newline character. + + Return value: the line read. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def read(self) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + + @overload + def read(self, size: int, /) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + def close(self) -> None: + """ + Mark the socket closed and release all resources. Once that happens, all future operations + on the socket object will fail. The remote end will receive EOF indication if + supported by protocol. + + Sockets are automatically closed when they are garbage-collected, but it is recommended + to `close()` them explicitly as soon you finished working with them. + """ + ... + def connect(self, address: _Address | bytes, /) -> None: + """ + Connect to a remote socket at *address*. + """ + ... + def send(self, bytes: AnyReadableBuf, /) -> int: + """ + Send data to the socket. The socket must be connected to a remote socket. + Returns number of bytes sent, which may be smaller than the length of data + ("short write"). + """ + ... + def bind(self, address: _Address | bytes, /) -> None: + """ + Bind the socket to *address*. The socket must not already be bound. + """ + ... + def accept(self) -> Tuple: + """ + Accept a connection. The socket must be bound to an address and listening for connections. + The return value is a pair (conn, address) where conn is a new socket object usable to send + and receive data on the connection, and address is the address bound to the socket on the + other end of the connection. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the buffer of bytes to the socket. This function will try to + write all data to a socket (no "short writes"). This may be not possible + with a non-blocking socket though, and returned value will be less than + the length of *buf*. + + Return value: number of bytes written. + """ + ... + def __init__( + self, + af: int = AF_INET, + type: int = SOCK_STREAM, + proto: int = IPPROTO_TCP, + /, + ) -> None: + """ + Create a new socket using the given address family, socket type and + protocol number. Note that specifying *proto* in most cases is not + required (and not recommended, as some MicroPython ports may omit + ``IPPROTO_*`` constants). Instead, *type* argument will select needed + protocol automatically:: + + # Create STREAM TCP socket + socket(AF_INET, SOCK_STREAM) + # Create DGRAM UDP socket + socket(AF_INET, SOCK_DGRAM) + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/time.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/time.pyi new file mode 100644 index 000000000..f2bbac553 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/time.pyi @@ -0,0 +1,306 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. + +--- +Module: 'time' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def ticks_diff(ticks1: _Ticks, ticks2: _Ticks, /) -> int: + """ + Measure ticks difference between values returned from `ticks_ms()`, `ticks_us()`, + or `ticks_cpu()` functions, as a signed value which may wrap around. + + The argument order is the same as for subtraction + operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. + However, values returned by `ticks_ms()`, etc. functions may wrap around, so + directly using subtraction on them will produce incorrect result. That is why + `ticks_diff()` is needed, it implements modular (or more specifically, ring) + arithmetic to produce correct result even for wrap-around values (as long as they not + too distant in between, see below). The function returns **signed** value in the range + [*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for + two's-complement signed binary integers). If the result is negative, it means that + *ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that + *ticks1* occurred after *ticks2*. This holds **only** if *ticks1* and *ticks2* + are apart from each other for no more than *TICKS_PERIOD/2-1* ticks. If that does + not hold, incorrect result will be returned. Specifically, if two tick values are + apart for *TICKS_PERIOD/2-1* ticks, that value will be returned by the function. + However, if *TICKS_PERIOD/2* of real-time ticks has passed between them, the + function will return *-TICKS_PERIOD/2* instead, i.e. result value will wrap around + to the negative range of possible values. + + Informal rationale of the constraints above: Suppose you are locked in a room with no + means to monitor passing of time except a standard 12-notch clock. Then if you look at + dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a + long sleep), then once you finally look again, it may seem to you that only 1 hour + has passed. To avoid this mistake, just look at the clock regularly. Your application + should do the same. "Too long sleep" metaphor also maps directly to application + behaviour: don't let your application run any single task for too long. Run tasks + in steps, and do time-keeping in between. + + `ticks_diff()` is designed to accommodate various usage patterns, among them: + + * Polling with timeout. In this case, the order of events is known, and you will deal + only with positive results of `ticks_diff()`:: + + # Wait for GPIO pin to be asserted, but at most 500us + start = time.ticks_us() + while pin.value() == 0: + if time.ticks_diff(time.ticks_us(), start) > 500: + raise TimeoutError + + * Scheduling events. In this case, `ticks_diff()` result may be negative + if an event is overdue:: + + # This code snippet is not optimized + now = time.ticks_ms() + scheduled_time = task.scheduled_time() + if ticks_diff(scheduled_time, now) > 0: + print("Too early, let's nap") + sleep_ms(ticks_diff(scheduled_time, now)) + task.run() + elif ticks_diff(scheduled_time, now) == 0: + print("Right at time!") + task.run() + elif ticks_diff(scheduled_time, now) < 0: + print("Oops, running late, tell task to run faster!") + task.run(run_faster=true) + + Note: Do not pass `time()` values to `ticks_diff()`, you should use + normal mathematical operations on them. But note that `time()` may (and will) + also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem . + """ + ... + +def ticks_add(ticks: _Ticks, delta: int, /) -> _Ticks: + """ + Offset ticks value by a given number, which can be either positive or negative. + Given a *ticks* value, this function allows to calculate ticks value *delta* + ticks before or after it, following modular-arithmetic definition of tick values + (see `ticks_ms()` above). *ticks* parameter must be a direct result of call + to `ticks_ms()`, `ticks_us()`, or `ticks_cpu()` functions (or from previous + call to `ticks_add()`). However, *delta* can be an arbitrary integer number + or numeric expression. `ticks_add()` is useful for calculating deadlines for + events/tasks. (Note: you must use `ticks_diff()` function to work with + deadlines.) + + Examples:: + + # Find out what ticks value there was 100ms ago + print(ticks_add(time.ticks_ms(), -100)) + + # Calculate deadline for operation and test for it + deadline = ticks_add(time.ticks_ms(), 200) + while ticks_diff(deadline, time.ticks_ms()) > 0: + do_a_little_of_something() + + # Find out TICKS_MAX used by this port + print(ticks_add(0, -1)) + """ + ... + +def ticks_cpu() -> _TicksCPU: + """ + Similar to `ticks_ms()` and `ticks_us()`, but with the highest possible resolution + in the system. This is usually CPU clocks, and that's why the function is named that + way. But it doesn't have to be a CPU clock, some other timing source available in a + system (e.g. high-resolution timer) can be used instead. The exact timing unit + (resolution) of this function is not specified on ``time`` module level, but + documentation for a specific port may provide more specific information. This + function is intended for very fine benchmarking or very tight real-time loops. + Avoid using it in portable code. + + Availability: Not every port implements this function. + """ + ... + +def time() -> int: + """ + Returns the number of seconds, as an integer, since the Epoch, assuming that + underlying RTC is set and maintained as described above. If an RTC is not set, this + function returns number of seconds since a port-specific reference point in time (for + embedded boards without a battery-backed RTC, usually since power up or reset). If you + want to develop portable MicroPython application, you should not rely on this function + to provide higher than second precision. If you need higher precision, absolute + timestamps, use `time_ns()`. If relative times are acceptable then use the + `ticks_ms()` and `ticks_us()` functions. If you need calendar time, `gmtime()` or + `localtime()` without an argument is a better choice. + + Admonition:Difference to CPython + :class: attention + + In CPython, this function returns number of + seconds since Unix epoch, 1970-01-01 00:00 UTC, as a floating-point, + usually having microsecond precision. With MicroPython, only Unix port + uses the same Epoch, and if floating-point precision allows, + returns sub-second precision. Embedded hardware usually doesn't have + floating-point precision to represent both long time ranges and subsecond + precision, so they use integer value with second precision. Some embedded + hardware also lacks battery-powered RTC, so returns number of seconds + since last power-up or from other relative, hardware-specific point + (e.g. reset). + """ + ... + +def ticks_ms() -> int: + """ + Returns an increasing millisecond counter with an arbitrary reference point, that + wraps around after some value. + + The wrap-around value is not explicitly exposed, but we will + refer to it as *TICKS_MAX* to simplify discussion. Period of the values is + *TICKS_PERIOD = TICKS_MAX + 1*. *TICKS_PERIOD* is guaranteed to be a power of + two, but otherwise may differ from port to port. The same period value is used + for all of `ticks_ms()`, `ticks_us()`, `ticks_cpu()` functions (for + simplicity). Thus, these functions will return a value in range [*0* .. + *TICKS_MAX*], inclusive, total *TICKS_PERIOD* values. Note that only + non-negative values are used. For the most part, you should treat values returned + by these functions as opaque. The only operations available for them are + `ticks_diff()` and `ticks_add()` functions described below. + + Note: Performing standard mathematical operations (+, -) or relational + operators (<, <=, >, >=) directly on these value will lead to invalid + result. Performing mathematical operations and then passing their results + as arguments to `ticks_diff()` or `ticks_add()` will also lead to + invalid results from the latter functions. + """ + ... + +def ticks_us() -> _TicksUs: + """ + Just like `ticks_ms()` above, but in microseconds. + """ + ... + +def time_ns() -> int: + """ + Similar to `time()` but returns nanoseconds since the Epoch, as an integer (usually + a big integer, so will allocate on the heap). + """ + ... + +def localtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_us(us: int, /) -> None: + """ + Delay for given number of microseconds, should be positive or 0. + + This function attempts to provide an accurate delay of at least *us* + microseconds, but it may take longer if the system has other higher priority + processing to perform. + """ + ... + +def gmtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_ms(ms: int, /) -> None: + """ + Delay for given number of milliseconds, should be positive or 0. + + This function will delay for at least the given number of milliseconds, but + may take longer than that if other processing must take place, for example + interrupt handlers or other threads. Passing in 0 for *ms* will still allow + this other processing to occur. Use `sleep_us()` for more precise delays. + """ + ... + +def mktime(local_time: _TimeTuple, /) -> int: + """ + This is inverse function of localtime. It's argument is a full 8-tuple + which expresses a time as per localtime. It returns an integer which is + the number of seconds since the time epoch. + """ + ... + +def sleep(seconds: float, /) -> None: + """ + Sleep for the given number of seconds. Some boards may accept *seconds* as a + floating-point number to sleep for a fractional number of seconds. Note that + other boards may not accept a floating-point argument, for compatibility with + them use `sleep_ms()` and `sleep_us()` functions. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uarray.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uarray.pyi new file mode 100644 index 000000000..e5c0fe438 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uarray.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to array +from array import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uasyncio.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uasyncio.pyi new file mode 100644 index 000000000..3d69c52f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uasyncio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to asyncio +from asyncio import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ubinascii.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ubinascii.pyi new file mode 100644 index 000000000..3a77380ad --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ubinascii.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to binascii +from binascii import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ubluetooth.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ubluetooth.pyi new file mode 100644 index 000000000..4046c2c75 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ubluetooth.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to bluetooth +from bluetooth import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ucollections.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ucollections.pyi new file mode 100644 index 000000000..9ca701c74 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ucollections.pyi @@ -0,0 +1,137 @@ +""" +Collection and container types. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/collections.html + +CPython module: :mod:`python:collections` https://docs.python.org/3/library/collections.html . + +This module implements advanced collection and container types to +hold/accumulate various objects. + +--- +Module: 'ucollections' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Generic, Tuple, Any, Final, Generator +from _typeshed import Incomplete +from collections.abc import Iterable +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_KT = TypeVar("_KT") +_VT = TypeVar("_VT") +_T = TypeVar("_T") + +def namedtuple(name: str, fields: str | Iterable[str]) -> type[Tuple[Any, ...]]: + """ + This is factory function to create a new namedtuple type with a specific + name and set of fields. A namedtuple is a subclass of tuple which allows + to access its fields not just by numeric index, but also with an attribute + access syntax using symbolic field names. Fields is a sequence of strings + specifying field names. For compatibility with CPython it can also be a + a string with space-separated field named (but this is less efficient). + Example of use:: + + from collections import namedtuple + + MyTuple = namedtuple("MyTuple", ("id", "name")) + t1 = MyTuple(1, "foo") + t2 = MyTuple(2, "bar") + print(t1.name) + assert t2.name == t2[1] + """ + ... + +class OrderedDict(Dict[_KT, _VT], Generic[_KT, _VT]): + """ + ``dict`` type subclass which remembers and preserves the order of keys + added. When ordered dict is iterated over, keys/items are returned in + the order they were added:: + + from collections import OrderedDict + + # To make benefit of ordered keys, OrderedDict should be initialized + # from sequence of (key, value) pairs. + d = OrderedDict([("z", 1), ("a", 2)]) + # More items can be added as usual + d["w"] = 5 + d["b"] = 3 + for k, v in d.items(): + print(k, v) + + Output:: + + z 1 + a 2 + w 5 + b 3 + """ + def popitem(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def values(self, *args, **kwargs) -> Incomplete: ... + def setdefault(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def keys(self, *args, **kwargs) -> Incomplete: ... + def get(self, *args, **kwargs) -> Incomplete: ... + def items(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromkeys(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *args, **kwargs) -> None: ... + +class deque: + """ + Minimal implementation of a deque that implements a FIFO buffer. + """ + def pop(self) -> Incomplete: + """ + Remove and return an item from the right side of the deque. + Raises ``IndexError`` if no items are present. + """ + ... + def appendleft(self, x: _T, /) -> Incomplete: + """ + Add *x* to the left side of the deque. + Raises ``IndexError`` if overflow checking is enabled and there is + no more room in the queue. + """ + ... + def popleft(self) -> Any: + """ + Remove and return an item from the left side of the deque. + Raises ``IndexError`` if no items are present. + """ + ... + def extend(self, iterable: Iterable[_T], /) -> Incomplete: + """ + Extend the deque by appending all the items from *iterable* to + the right of the deque. + Raises ``IndexError`` if overflow checking is enabled and there is + no more room in the deque. + """ + ... + def append(self, x: _T, /) -> None: + """ + Add *x* to the right side of the deque. + Raises ``IndexError`` if overflow checking is enabled and there is + no more room in the queue. + """ + ... + def __init__(self, iterable: tuple[Any], maxlen: int, flags: int = 0, /) -> None: + """ + Deques (double-ended queues) are a list-like container that support O(1) + appends and pops from either side of the deque. New deques are created + using the following arguments: + + - *iterable* must be the empty tuple, and the new deque is created empty. + + - *maxlen* must be specified and the deque will be bounded to this + maximum length. Once the deque is full, any new items added will + discard items from the opposite end. + + - The optional *flags* can be 1 to check for overflow when adding items. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ucryptolib.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ucryptolib.pyi new file mode 100644 index 000000000..6b8b56a68 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ucryptolib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to cryptolib +from cryptolib import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uctypes.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uctypes.pyi new file mode 100644 index 000000000..76f7e77ab --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uctypes.pyi @@ -0,0 +1,164 @@ +""" +Access binary data in a structured way. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/uctypes.html + +This module implements "foreign data interface" for MicroPython. The idea +behind it is similar to CPython's ``ctypes`` modules, but the actual API is +different, streamlined and optimized for small size. The basic idea of the +module is to define data structure layout with about the same power as the +C language allows, and then access it using familiar dot-syntax to reference +sub-fields. + +--- +Module: 'uctypes' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Tuple, Any, Final, Generator +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +VOID: Final[int] = 0 +"""\ +``VOID`` is an alias for ``UINT8``, and is provided to conveniently define +C's void pointers: ``(uctypes.PTR, uctypes.VOID)``. +""" +NATIVE: Final[int] = 2 +"""\ +Layout type for a native structure - with data endianness and alignment +conforming to the ABI of the system on which MicroPython runs. +""" +PTR: Final[int] = 536870912 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +SHORT: Final[int] = 402653184 +LONGLONG: Final[int] = 939524096 +INT8: Final[int] = 134217728 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +LITTLE_ENDIAN: Final[int] = 0 +"""\ +Layout type for a little-endian packed structure. (Packed means that every +field occupies exactly as many bytes as defined in the descriptor, i.e. +the alignment is 1). +""" +LONG: Final[int] = 671088640 +UINT: Final[int] = 536870912 +ULONG: Final[int] = 536870912 +ULONGLONG: Final[int] = 805306368 +USHORT: Final[int] = 268435456 +UINT8: Final[int] = 0 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT16: Final[int] = 268435456 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT32: Final[int] = 536870912 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT64: Final[int] = 805306368 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT64: Final[int] = 939524096 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +BFUINT16: Final[int] = -805306368 +BFUINT32: Final[int] = -536870912 +BFUINT8: Final[int] = -1073741824 +BFINT8: Final[int] = -939524096 +ARRAY: Final[int] = -1073741824 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +BFINT16: Final[int] = -671088640 +BFINT32: Final[int] = -402653184 +BF_LEN: Final[int] = 22 +INT: Final[int] = 671088640 +INT16: Final[int] = 402653184 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT32: Final[int] = 671088640 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +FLOAT64: Final[int] = -134217728 +"""Floating-point types for structure descriptors.""" +BF_POS: Final[int] = 17 +BIG_ENDIAN: Final[int] = 1 +"""Layout type for a big-endian packed structure.""" +FLOAT32: Final[int] = -268435456 +"""Floating-point types for structure descriptors.""" +_property: TypeAlias = Incomplete +_descriptor: TypeAlias = Tuple | Dict + +def sizeof(struct: struct | _descriptor | dict, layout_type: int = NATIVE, /) -> int: + """ + Return size of data structure in bytes. The *struct* argument can be + either a structure class or a specific instantiated structure object + (or its aggregate field). + """ + ... + +def bytes_at(addr: int, size: int, /) -> bytes: + """ + Capture memory at the given address and size as bytes object. As bytes + object is immutable, memory is actually duplicated and copied into + bytes object, so if memory contents change later, created object + retains original value. + """ + ... + +def bytearray_at(addr: int, size: int, /) -> bytearray: + """ + Capture memory at the given address and size as bytearray object. + Unlike bytes_at() function above, memory is captured by reference, + so it can be both written too, and you will access current value + at the given memory address. + """ + ... + +def addressof(obj: AnyReadableBuf, /) -> int: + """ + Return address of an object. Argument should be bytes, bytearray or + other object supporting buffer protocol (and address of this buffer + is what actually returned). + """ + ... + +class struct: + """ + Module contents + --------------- + """ + def __init__(self, addr: int | struct, descriptor: _descriptor, layout_type: int = NATIVE, /) -> None: + """ + Instantiate a "foreign data structure" object based on structure address in + memory, descriptor (encoded as a dictionary), and layout type (see below). + """ + ... + @mp_available() # force push + def __getattr__(self, a): ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uerrno.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uerrno.pyi new file mode 100644 index 000000000..8d34ba6b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uerrno.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to errno +from errno import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uhashlib.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uhashlib.pyi new file mode 100644 index 000000000..8b4b7bc77 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uhashlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to hashlib +from hashlib import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uheapq.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uheapq.pyi new file mode 100644 index 000000000..71c066fcf --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uheapq.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to heapq +from heapq import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uio.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uio.pyi new file mode 100644 index 000000000..514a4f945 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to io +from io import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ujson.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ujson.pyi new file mode 100644 index 000000000..0de669254 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ujson.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to json +from json import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/umachine.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/umachine.pyi new file mode 100644 index 000000000..e1fdb35a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/umachine.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to machine +from machine import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uos.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uos.pyi new file mode 100644 index 000000000..8c99e764b --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uos.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to os +from os import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uplatform.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uplatform.pyi new file mode 100644 index 000000000..22ad247bf --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uplatform.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to platform +from platform import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/urandom.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/urandom.pyi new file mode 100644 index 000000000..b912f0793 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/urandom.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to random +from random import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ure.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ure.pyi new file mode 100644 index 000000000..dbe8b6a52 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ure.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to re +from re import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usb/device.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usb/device.pyi new file mode 100644 index 000000000..467e898ef --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usb/device.pyi @@ -0,0 +1,10 @@ +""" +Module: 'usb.device' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def get(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usb/device/cdc.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usb/device/cdc.pyi new file mode 100644 index 000000000..a95da0691 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usb/device/cdc.pyi @@ -0,0 +1,77 @@ +""" +Module: 'usb.device.cdc' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +_STOP_BITS_REPR: tuple = () +_PARITY_BITS_REPR: Final[str] = "NOEMS" + +def split_bmRequestType(*args, **kwargs) -> Incomplete: ... +def const(*args, **kwargs) -> Incomplete: ... + +class Buffer: + def finish_read(self, *args, **kwargs) -> Incomplete: ... + def pend_write(self, *args, **kwargs) -> Incomplete: ... + def finish_write(self, *args, **kwargs) -> Incomplete: ... + def pend_read(self, *args, **kwargs) -> Incomplete: ... + def readable(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def writable(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Interface: + def on_interface_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def stall(self, *args, **kwargs) -> Incomplete: ... + def on_device_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def xfer_pending(self, *args, **kwargs) -> Incomplete: ... + def on_endpoint_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def is_open(self, *args, **kwargs) -> Incomplete: ... + def num_itfs(self, *args, **kwargs) -> Incomplete: ... + def submit_xfer(self, *args, **kwargs) -> Incomplete: ... + def desc_cfg(self, *args, **kwargs) -> Incomplete: ... + def on_reset(self, *args, **kwargs) -> Incomplete: ... + def num_eps(self, *args, **kwargs) -> Incomplete: ... + def on_open(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class CDCInterface: + def xfer_pending(self, *args, **kwargs) -> Incomplete: ... + def is_open(self, *args, **kwargs) -> Incomplete: ... + def stall(self, *args, **kwargs) -> Incomplete: ... + def _readinto(self, *args, **kwargs) -> Incomplete: ... + def on_device_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def on_endpoint_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def on_interface_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def _wr_cb(self, *args, **kwargs) -> Incomplete: ... + def _wr_xfer(self, *args, **kwargs) -> Incomplete: ... + def _rd_cb(self, *args, **kwargs) -> Incomplete: ... + def set_break_cb(self, *args, **kwargs) -> Incomplete: ... + def set_line_state_cb(self, *args, **kwargs) -> Incomplete: ... + def _rd_xfer(self, *args, **kwargs) -> Incomplete: ... + def set_line_coding_cb(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def submit_xfer(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def num_eps(self, *args, **kwargs) -> Incomplete: ... + def desc_cfg(self, *args, **kwargs) -> Incomplete: ... + def num_itfs(self, *args, **kwargs) -> Incomplete: ... + def on_reset(self, *args, **kwargs) -> Incomplete: ... + def on_open(self, *args, **kwargs) -> Incomplete: ... + + baudrate: Incomplete ## = + rts: Incomplete ## = + parity: Incomplete ## = + dtr: Incomplete ## = + stop_bits: Incomplete ## = + data_bits: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uselect.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uselect.pyi new file mode 100644 index 000000000..a543041c4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uselect.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to select +from select import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usocket.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usocket.pyi new file mode 100644 index 000000000..140590c29 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to socket +from socket import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ussl.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ussl.pyi new file mode 100644 index 000000000..3115761c4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ussl.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to ssl +from ssl import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ustruct.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ustruct.pyi new file mode 100644 index 000000000..0f7fb657a --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/ustruct.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to struct +from struct import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usys.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usys.pyi new file mode 100644 index 000000000..298d7a8ac --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/usys.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to sys +from sys import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/utime.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/utime.pyi new file mode 100644 index 000000000..1f972a5b6 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/utime.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to time +from time import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uwebsocket.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uwebsocket.pyi new file mode 100644 index 000000000..afa801ba2 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uwebsocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to websocket +from websocket import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uzlib.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uzlib.pyi new file mode 100644 index 000000000..5fad9a23c --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/uzlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to zlib +from zlib import * diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/vfs.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/vfs.pyi new file mode 100644 index 000000000..6f915de3f --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged/vfs.pyi @@ -0,0 +1,240 @@ +""" +Virtual filesystem control. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/vfs.html + +The ``vfs`` module contains functions for creating filesystem objects and +mounting/unmounting them in the Virtual Filesystem. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +--- +Module: 'vfs' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _BlockDeviceProtocol +from abc import ABC, abstractmethod +from typing import List, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def umount(mount_point: Incomplete) -> Incomplete: + """ + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + """ + ... + +@overload +def mount(fsobj, mount_point: str, *, readonly: bool = False) -> None: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +@overload +def mount() -> List[tuple[Incomplete, str]]: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +class VfsLfs2: + """ + Create a filesystem object that uses the `littlefs v2 filesystem format`_. + Storage of the littlefs filesystem is provided by *block_dev*, which must + support the :ref:`extended interface `. + Objects created by this constructor can be mounted using :func:`mount`. + + The *mtime* argument enables modification timestamps for files, stored using + littlefs attributes. This option can be disabled or enabled differently each + mount time and timestamps will only be added or updated if *mtime* is enabled, + otherwise the timestamps will remain untouched. Littlefs v2 filesystems without + timestamps will work without reformatting and timestamps will be added + transparently to existing files once they are opened for writing. When *mtime* + is enabled `os.stat` on files without timestamps will return 0 for the timestamp. + + See :ref:`filesystem` for more information. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32) -> None: + """ + Build a Lfs2 filesystem on *block_dev*. + + ``Note:`` There are reports of littlefs v2 failing in certain situations, + for details see `littlefs issue 295`_. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32, mtime=True) -> None: ... + +class VfsFat: + """ + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev) -> None: + """ + Build a FAT filesystem on *block_dev*. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev) -> None: ... + +class AbstractBlockDev: + # + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: ... + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + ... + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + ... + + @abstractmethod + @overload + def ioctl(self, op: int, arg) -> int | None: ... + # + @abstractmethod + @overload + def ioctl(self, op: int) -> int | None: + """ + Control the block device and query its parameters. The operation to + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 5 -- get the number of bytes in a block, should return an integer, + or ``None`` in which case the default value of 512 is used + (*arg* is unused) + - 6 -- erase a block, *arg* is the block number to erase + + As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs + ``ioctl(6, ...)`` must also be intercepted. The need for others is + hardware dependent. + + Prior to any call to ``writeblocks(block, ...)`` littlefs issues + ``ioctl(6, block)``. This enables a device driver to erase the block + prior to a write if the hardware requires it. Alternatively a driver + might intercept ``ioctl(6, block)`` and return 0 (success). In this case + the driver assumes responsibility for detecting the need for erasure. + + Unless otherwise stated ``ioctl(op, arg)`` can return ``None``. + Consequently an implementation can ignore unused values of ``op``. Where + ``op`` is intercepted, the return value for operations 4 and 5 are as + detailed above. Other operations should return 0 on success and non-zero + for failure, with the value returned being an ``OSError`` errno code. + """ + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_asyncio.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_asyncio.pyi new file mode 100644 index 000000000..1fdf76b11 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_asyncio.pyi @@ -0,0 +1,18 @@ +""" +Module: '_asyncio' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class TaskQueue: + def push(self, *args, **kwargs) -> Incomplete: ... + def peek(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Task: + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_onewire.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_onewire.pyi new file mode 100644 index 000000000..20bb1a901 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_onewire.pyi @@ -0,0 +1,15 @@ +""" +Module: '_onewire' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def reset(*args, **kwargs) -> Incomplete: ... +def writebyte(*args, **kwargs) -> Incomplete: ... +def writebit(*args, **kwargs) -> Incomplete: ... +def crc8(*args, **kwargs) -> Incomplete: ... +def readbyte(*args, **kwargs) -> Incomplete: ... +def readbit(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/array.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/array.pyi new file mode 100644 index 000000000..ccbd5fbe0 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/array.pyi @@ -0,0 +1,13 @@ +""" +Module: 'array' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class array: + def extend(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/__init__.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/__init__.pyi new file mode 100644 index 000000000..e1d11dbe5 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/__init__.pyi @@ -0,0 +1,278 @@ +""" +Module: 'asyncio.__init__' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +_attrs: dict = {} +def current_task(*args, **kwargs) -> Incomplete: + ... + +def get_event_loop(*args, **kwargs) -> Incomplete: + ... + +def create_task(*args, **kwargs) -> Incomplete: + ... + +def ticks_diff(*args, **kwargs) -> Incomplete: + ... + +def new_event_loop(*args, **kwargs) -> Incomplete: + ... + +def ticks(*args, **kwargs) -> Incomplete: + ... + +def run_until_complete(*args, **kwargs) -> Incomplete: + ... + +def run(*args, **kwargs) -> Incomplete: + ... + +def wait_for_ms(*args, **kwargs) -> Incomplete: + ... + +def sleep_ms(*args, **kwargs) -> Incomplete: + ... + +def ticks_add(*args, **kwargs) -> Incomplete: + ... + +def sleep(*args, **kwargs) -> Incomplete: + ... + + +class TaskQueue(): + def push(self, *args, **kwargs) -> Incomplete: + ... + + def peek(self, *args, **kwargs) -> Incomplete: + ... + + def remove(self, *args, **kwargs) -> Incomplete: + ... + + def pop(self, *args, **kwargs) -> Incomplete: + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + +def open_connection(*args, **kwargs) -> Generator: ## = + ... + +cur_task: Incomplete ## = None +def gather(*args, **kwargs) -> Generator: ## = + ... + + +class Task(): + def __init__(self, *argv, **kwargs) -> None: + ... + +def wait_for(*args, **kwargs) -> Generator: ## = + ... + + +class CancelledError(Exception): + ... +def start_server(*args, **kwargs) -> Generator: ## = + ... + + +class Lock(): + def locked(self, *args, **kwargs) -> Incomplete: + ... + + def release(self, *args, **kwargs) -> Incomplete: + ... + + def acquire(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class StreamWriter(): + def write(self, *args, **kwargs) -> Incomplete: + ... + + def get_extra_info(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def awritestr(*args, **kwargs) -> Generator: ## = + ... + + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + + def drain(*args, **kwargs) -> Generator: ## = + ... + + def readexactly(*args, **kwargs) -> Generator: ## = + ... + + def readinto(*args, **kwargs) -> Generator: ## = + ... + + def read(*args, **kwargs) -> Generator: ## = + ... + + def awrite(*args, **kwargs) -> Generator: ## = + ... + + def readline(*args, **kwargs) -> Generator: ## = + ... + + def aclose(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class StreamReader(): + def write(self, *args, **kwargs) -> Incomplete: + ... + + def get_extra_info(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def awritestr(*args, **kwargs) -> Generator: ## = + ... + + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + + def drain(*args, **kwargs) -> Generator: ## = + ... + + def readexactly(*args, **kwargs) -> Generator: ## = + ... + + def readinto(*args, **kwargs) -> Generator: ## = + ... + + def read(*args, **kwargs) -> Generator: ## = + ... + + def awrite(*args, **kwargs) -> Generator: ## = + ... + + def readline(*args, **kwargs) -> Generator: ## = + ... + + def aclose(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class SingletonGenerator(): + def __init__(self, *argv, **kwargs) -> None: + ... + + +class Loop(): + def get_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def default_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def set_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def run_forever(self, *args, **kwargs) -> Incomplete: + ... + + def run_until_complete(self, *args, **kwargs) -> Incomplete: + ... + + def stop(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def create_task(self, *args, **kwargs) -> Incomplete: + ... + + def call_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + _exc_handler: Incomplete ## = None + def __init__(self, *argv, **kwargs) -> None: + ... + + +class Event(): + def set(self, *args, **kwargs) -> Incomplete: + ... + + def is_set(self, *args, **kwargs) -> Incomplete: + ... + + def clear(self, *args, **kwargs) -> Incomplete: + ... + + def wait(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class ThreadSafeFlag(): + def set(self, *args, **kwargs) -> Incomplete: + ... + + def ioctl(self, *args, **kwargs) -> Incomplete: + ... + + def clear(self, *args, **kwargs) -> Incomplete: + ... + + def wait(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class IOQueue(): + def queue_read(self, *args, **kwargs) -> Incomplete: + ... + + def wait_io_event(self, *args, **kwargs) -> Incomplete: + ... + + def queue_write(self, *args, **kwargs) -> Incomplete: + ... + + def remove(self, *args, **kwargs) -> Incomplete: + ... + + def _enqueue(self, *args, **kwargs) -> Incomplete: + ... + + def _dequeue(self, *args, **kwargs) -> Incomplete: + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class TimeoutError(Exception): + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/core.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/core.pyi new file mode 100644 index 000000000..115ac7570 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/core.pyi @@ -0,0 +1,73 @@ +""" +Module: 'asyncio.core' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +_exc_context: dict = {} + +def ticks(*args, **kwargs) -> Incomplete: ... +def create_task(*args, **kwargs) -> Incomplete: ... +def _promote_to_task(*args, **kwargs) -> Incomplete: ... +def ticks_diff(*args, **kwargs) -> Incomplete: ... +def run(*args, **kwargs) -> Incomplete: ... +def run_until_complete(*args, **kwargs) -> Incomplete: ... +def current_task(*args, **kwargs) -> Incomplete: ... +def new_event_loop(*args, **kwargs) -> Incomplete: ... +def get_event_loop(*args, **kwargs) -> Incomplete: ... +def sleep_ms(*args, **kwargs) -> Incomplete: ... +def ticks_add(*args, **kwargs) -> Incomplete: ... +def sleep(*args, **kwargs) -> Incomplete: ... + +cur_task: Incomplete ## = None +_task_queue: Incomplete ## = + +class Loop: + def get_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def default_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def set_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def run_forever(self, *args, **kwargs) -> Incomplete: ... + def run_until_complete(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def create_task(self, *args, **kwargs) -> Incomplete: ... + def call_exception_handler(self, *args, **kwargs) -> Incomplete: ... + + _exc_handler: Incomplete ## = None + def __init__(self, *argv, **kwargs) -> None: ... + +class CancelledError(Exception): ... + +class TaskQueue: + def push(self, *args, **kwargs) -> Incomplete: ... + def peek(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Task: + def __init__(self, *argv, **kwargs) -> None: ... + +class TimeoutError(Exception): ... + +class IOQueue: + def queue_read(self, *args, **kwargs) -> Incomplete: ... + def wait_io_event(self, *args, **kwargs) -> Incomplete: ... + def queue_write(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def _enqueue(self, *args, **kwargs) -> Incomplete: ... + def _dequeue(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SingletonGenerator: + def __init__(self, *argv, **kwargs) -> None: ... + +def _stopper(*args, **kwargs) -> Generator: ## = + ... + +_stop_task: Incomplete ## = None +_io_queue: Incomplete ## = diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/event.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/event.pyi new file mode 100644 index 000000000..8aac4fed9 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/event.pyi @@ -0,0 +1,25 @@ +""" +Module: 'asyncio.event' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +class ThreadSafeFlag: + def set(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def wait(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Event: + def set(self, *args, **kwargs) -> Incomplete: ... + def is_set(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def wait(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/funcs.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/funcs.pyi new file mode 100644 index 000000000..6412e49d7 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/funcs.pyi @@ -0,0 +1,22 @@ +""" +Module: 'asyncio.funcs' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +def wait_for_ms(*args, **kwargs) -> Incomplete: ... +def gather(*args, **kwargs) -> Generator: ## = + ... +def wait_for(*args, **kwargs) -> Generator: ## = + ... + +class _Remove: + def remove(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +def _run(*args, **kwargs) -> Generator: ## = + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/lock.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/lock.pyi new file mode 100644 index 000000000..c1ce32915 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/lock.pyi @@ -0,0 +1,16 @@ +""" +Module: 'asyncio.lock' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +class Lock: + def locked(self, *args, **kwargs) -> Incomplete: ... + def release(self, *args, **kwargs) -> Incomplete: ... + def acquire(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/stream.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/stream.pyi new file mode 100644 index 000000000..47dfbb7fc --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/stream.pyi @@ -0,0 +1,96 @@ +""" +Module: 'asyncio.stream' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +def stream_awrite(*args, **kwargs) -> Generator: ## = + ... +def open_connection(*args, **kwargs) -> Generator: ## = + ... +def start_server(*args, **kwargs) -> Generator: ## = + ... + +class StreamWriter: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Server: + def close(self, *args, **kwargs) -> Incomplete: ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def _serve(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Stream: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class StreamReader: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/binascii.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/binascii.pyi new file mode 100644 index 000000000..1633ef766 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/binascii.pyi @@ -0,0 +1,14 @@ +""" +Module: 'binascii' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def crc32(*args, **kwargs) -> Incomplete: ... +def hexlify(*args, **kwargs) -> Incomplete: ... +def unhexlify(*args, **kwargs) -> Incomplete: ... +def b2a_base64(*args, **kwargs) -> Incomplete: ... +def a2b_base64(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/builtins.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/builtins.pyi new file mode 100644 index 000000000..d53be4937 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/builtins.pyi @@ -0,0 +1,305 @@ +""" +Module: 'builtins' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def any(*args, **kwargs) -> Incomplete: ... +def all(*args, **kwargs) -> Incomplete: ... +def len(*args, **kwargs) -> Incomplete: ... +def id(*args, **kwargs) -> Incomplete: ... +def sum(*args, **kwargs) -> Incomplete: ... +def issubclass(*args, **kwargs) -> Incomplete: ... +def iter(*args, **kwargs) -> Incomplete: ... +def abs(*args, **kwargs) -> Incomplete: ... +def isinstance(*args, **kwargs) -> Incomplete: ... +def setattr(*args, **kwargs) -> Incomplete: ... +def eval(*args, **kwargs) -> Incomplete: ... +def divmod(*args, **kwargs) -> Incomplete: ... +def hash(*args, **kwargs) -> Incomplete: ... +def exec(*args, **kwargs) -> Incomplete: ... +def getattr(*args, **kwargs) -> Incomplete: ... +def chr(*args, **kwargs) -> Incomplete: ... +def callable(*args, **kwargs) -> Incomplete: ... +def dir(*args, **kwargs) -> Incomplete: ... +def hasattr(*args, **kwargs) -> Incomplete: ... +def sorted(*args, **kwargs) -> Incomplete: ... +def globals(*args, **kwargs) -> Incomplete: ... +def max(*args, **kwargs) -> Incomplete: ... +def input(*args, **kwargs) -> Incomplete: ... +def hex(*args, **kwargs) -> Incomplete: ... +def help(*args, **kwargs) -> Incomplete: ... +def open(*args, **kwargs) -> Incomplete: ... +def ord(*args, **kwargs) -> Incomplete: ... +def pow(*args, **kwargs) -> Incomplete: ... +def oct(*args, **kwargs) -> Incomplete: ... +def min(*args, **kwargs) -> Incomplete: ... +def print(*args, **kwargs) -> Incomplete: ... +def repr(*args, **kwargs) -> Incomplete: ... +def locals(*args, **kwargs) -> Incomplete: ... +def compile(*args, **kwargs) -> Incomplete: ... +def bin(*args, **kwargs) -> Incomplete: ... +def execfile(*args, **kwargs) -> Incomplete: ... +def next(*args, **kwargs) -> Incomplete: ... +def delattr(*args, **kwargs) -> Incomplete: ... +def round(*args, **kwargs) -> Incomplete: ... + +NotImplemented: Incomplete ## = NotImplemented +Ellipsis: Incomplete ## = Ellipsis + +class set: + def discard(self, *args, **kwargs) -> Incomplete: ... + def isdisjoint(self, *args, **kwargs) -> Incomplete: ... + def intersection_update(self, *args, **kwargs) -> Incomplete: ... + def intersection(self, *args, **kwargs) -> Incomplete: ... + def issubset(self, *args, **kwargs) -> Incomplete: ... + def symmetric_difference_update(self, *args, **kwargs) -> Incomplete: ... + def symmetric_difference(self, *args, **kwargs) -> Incomplete: ... + def issuperset(self, *args, **kwargs) -> Incomplete: ... + def union(self, *args, **kwargs) -> Incomplete: ... + def difference_update(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def difference(self, *args, **kwargs) -> Incomplete: ... + def add(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class slice: + def __init__(self, *argv, **kwargs) -> None: ... + +class complex: + def __init__(self, *argv, **kwargs) -> None: ... + +class float: + def __init__(self, *argv, **kwargs) -> None: ... + +class filter: + def __init__(self, *argv, **kwargs) -> None: ... + +class enumerate: + def __init__(self, *argv, **kwargs) -> None: ... + +class frozenset: + def union(self, *args, **kwargs) -> Incomplete: ... + def issubset(self, *args, **kwargs) -> Incomplete: ... + def issuperset(self, *args, **kwargs) -> Incomplete: ... + def symmetric_difference(self, *args, **kwargs) -> Incomplete: ... + def isdisjoint(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def difference(self, *args, **kwargs) -> Incomplete: ... + def intersection(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class reversed: + def __init__(self, *argv, **kwargs) -> None: ... + +class property: + def getter(self, *args, **kwargs) -> Incomplete: ... + def setter(self, *args, **kwargs) -> Incomplete: ... + def deleter(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class memoryview: + def hex(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class ViperTypeError(Exception): ... + +class tuple: + def index(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class super: + def __init__(self, *argv, **kwargs) -> None: ... + +class str: + def rstrip(self, *args, **kwargs) -> Incomplete: ... + def startswith(self, *args, **kwargs) -> Incomplete: ... + def split(self, *args, **kwargs) -> Incomplete: ... + def rfind(self, *args, **kwargs) -> Incomplete: ... + def rsplit(self, *args, **kwargs) -> Incomplete: ... + def rindex(self, *args, **kwargs) -> Incomplete: ... + def replace(self, *args, **kwargs) -> Incomplete: ... + def partition(self, *args, **kwargs) -> Incomplete: ... + def strip(self, *args, **kwargs) -> Incomplete: ... + def rpartition(self, *args, **kwargs) -> Incomplete: ... + def upper(self, *args, **kwargs) -> Incomplete: ... + def encode(self, *args, **kwargs) -> Incomplete: ... + def center(self, *args, **kwargs) -> Incomplete: ... + def splitlines(self, *args, **kwargs) -> Incomplete: ... + def format(self, *args, **kwargs) -> Incomplete: ... + def isalpha(self, *args, **kwargs) -> Incomplete: ... + def index(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def find(self, *args, **kwargs) -> Incomplete: ... + def endswith(self, *args, **kwargs) -> Incomplete: ... + def lstrip(self, *args, **kwargs) -> Incomplete: ... + def join(self, *args, **kwargs) -> Incomplete: ... + def isdigit(self, *args, **kwargs) -> Incomplete: ... + def lower(self, *args, **kwargs) -> Incomplete: ... + def islower(self, *args, **kwargs) -> Incomplete: ... + def isupper(self, *args, **kwargs) -> Incomplete: ... + def isspace(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class type: + def __init__(self, *argv, **kwargs) -> None: ... + +class UnicodeError(Exception): ... + +class StopAsyncIteration: + def __init__(self, *argv, **kwargs) -> None: ... + +class zip: + def __init__(self, *argv, **kwargs) -> None: ... + +class IndentationError(Exception): ... +class KeyboardInterrupt(Exception): ... +class KeyError(Exception): ... +class IndexError(Exception): ... +class LookupError(Exception): ... +class NotImplementedError(Exception): ... +class NameError(Exception): ... +class MemoryError(Exception): ... +class OSError(Exception): ... +class ImportError(Exception): ... +class AttributeError(Exception): ... +class AssertionError(Exception): ... +class ArithmeticError(Exception): ... + +class GeneratorExit: + def __init__(self, *argv, **kwargs) -> None: ... + +class EOFError(Exception): ... + +class range: + def __init__(self, *argv, **kwargs) -> None: ... + +class bytearray: + def rstrip(self, *args, **kwargs) -> Incomplete: ... + def rsplit(self, *args, **kwargs) -> Incomplete: ... + def split(self, *args, **kwargs) -> Incomplete: ... + def startswith(self, *args, **kwargs) -> Incomplete: ... + def replace(self, *args, **kwargs) -> Incomplete: ... + def rindex(self, *args, **kwargs) -> Incomplete: ... + def rfind(self, *args, **kwargs) -> Incomplete: ... + def splitlines(self, *args, **kwargs) -> Incomplete: ... + def partition(self, *args, **kwargs) -> Incomplete: ... + def hex(self, *args, **kwargs) -> Incomplete: ... + def rpartition(self, *args, **kwargs) -> Incomplete: ... + def strip(self, *args, **kwargs) -> Incomplete: ... + def upper(self, *args, **kwargs) -> Incomplete: ... + def decode(self, *args, **kwargs) -> Incomplete: ... + def center(self, *args, **kwargs) -> Incomplete: ... + def find(self, *args, **kwargs) -> Incomplete: ... + def extend(self, *args, **kwargs) -> Incomplete: ... + def format(self, *args, **kwargs) -> Incomplete: ... + def index(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def endswith(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def lstrip(self, *args, **kwargs) -> Incomplete: ... + def isalpha(self, *args, **kwargs) -> Incomplete: ... + def isupper(self, *args, **kwargs) -> Incomplete: ... + def join(self, *args, **kwargs) -> Incomplete: ... + def lower(self, *args, **kwargs) -> Incomplete: ... + def islower(self, *args, **kwargs) -> Incomplete: ... + def isdigit(self, *args, **kwargs) -> Incomplete: ... + def isspace(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromhex(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class dict: + def popitem(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def values(self, *args, **kwargs) -> Incomplete: ... + def setdefault(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def keys(self, *args, **kwargs) -> Incomplete: ... + def get(self, *args, **kwargs) -> Incomplete: ... + def items(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromkeys(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class bytes: + def split(self, *args, **kwargs) -> Incomplete: ... + def rstrip(self, *args, **kwargs) -> Incomplete: ... + def startswith(self, *args, **kwargs) -> Incomplete: ... + def splitlines(self, *args, **kwargs) -> Incomplete: ... + def rfind(self, *args, **kwargs) -> Incomplete: ... + def rsplit(self, *args, **kwargs) -> Incomplete: ... + def rindex(self, *args, **kwargs) -> Incomplete: ... + def partition(self, *args, **kwargs) -> Incomplete: ... + def hex(self, *args, **kwargs) -> Incomplete: ... + def rpartition(self, *args, **kwargs) -> Incomplete: ... + def strip(self, *args, **kwargs) -> Incomplete: ... + def upper(self, *args, **kwargs) -> Incomplete: ... + def decode(self, *args, **kwargs) -> Incomplete: ... + def center(self, *args, **kwargs) -> Incomplete: ... + def index(self, *args, **kwargs) -> Incomplete: ... + def format(self, *args, **kwargs) -> Incomplete: ... + def isalpha(self, *args, **kwargs) -> Incomplete: ... + def replace(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def find(self, *args, **kwargs) -> Incomplete: ... + def endswith(self, *args, **kwargs) -> Incomplete: ... + def isdigit(self, *args, **kwargs) -> Incomplete: ... + def join(self, *args, **kwargs) -> Incomplete: ... + def lower(self, *args, **kwargs) -> Incomplete: ... + def lstrip(self, *args, **kwargs) -> Incomplete: ... + def isspace(self, *args, **kwargs) -> Incomplete: ... + def islower(self, *args, **kwargs) -> Incomplete: ... + def isupper(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromhex(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class int: + def to_bytes(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def from_bytes(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class object: + def __init__(self, *argv, **kwargs) -> None: ... + +class map: + def __init__(self, *argv, **kwargs) -> None: ... + +class list: + def pop(self, *args, **kwargs) -> Incomplete: ... + def insert(self, *args, **kwargs) -> Incomplete: ... + def index(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def reverse(self, *args, **kwargs) -> Incomplete: ... + def sort(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def extend(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def count(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class OverflowError(Exception): ... + +class bool: + def __init__(self, *argv, **kwargs) -> None: ... + +class SyntaxError(Exception): ... +class StopIteration(Exception): ... +class RuntimeError(Exception): ... +class SystemExit(Exception): ... +class ZeroDivisionError(Exception): ... +class ValueError(Exception): ... +class TypeError(Exception): ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/cmath.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/cmath.pyi new file mode 100644 index 000000000..ad5470821 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/cmath.pyi @@ -0,0 +1,21 @@ +""" +Module: 'cmath' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +e: float = 2.7182818 +pi: float = 3.1415928 + +def polar(*args, **kwargs) -> Incomplete: ... +def sqrt(*args, **kwargs) -> Incomplete: ... +def rect(*args, **kwargs) -> Incomplete: ... +def sin(*args, **kwargs) -> Incomplete: ... +def exp(*args, **kwargs) -> Incomplete: ... +def cos(*args, **kwargs) -> Incomplete: ... +def phase(*args, **kwargs) -> Incomplete: ... +def log(*args, **kwargs) -> Incomplete: ... +def log10(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/collections.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/collections.pyi new file mode 100644 index 000000000..3119d7a95 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/collections.pyi @@ -0,0 +1,33 @@ +""" +Module: 'collections' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def namedtuple(*args, **kwargs) -> Incomplete: ... + +class OrderedDict: + def popitem(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def values(self, *args, **kwargs) -> Incomplete: ... + def setdefault(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def keys(self, *args, **kwargs) -> Incomplete: ... + def get(self, *args, **kwargs) -> Incomplete: ... + def items(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromkeys(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class deque: + def pop(self, *args, **kwargs) -> Incomplete: ... + def appendleft(self, *args, **kwargs) -> Incomplete: ... + def popleft(self, *args, **kwargs) -> Incomplete: ... + def extend(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/deflate.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/deflate.pyi new file mode 100644 index 000000000..3cdd312ed --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/deflate.pyi @@ -0,0 +1,22 @@ +""" +Module: 'deflate' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +GZIP: Final[int] = 3 +RAW: Final[int] = 1 +ZLIB: Final[int] = 2 +AUTO: Final[int] = 0 + +class DeflateIO: + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/dht.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/dht.pyi new file mode 100644 index 000000000..f6c87a348 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/dht.pyi @@ -0,0 +1,26 @@ +""" +Module: 'dht' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def dht_readinto(*args, **kwargs) -> Incomplete: ... + +class DHTBase: + def measure(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT22: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class DHT11: + def measure(self, *args, **kwargs) -> Incomplete: ... + def temperature(self, *args, **kwargs) -> Incomplete: ... + def humidity(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ds18x20.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ds18x20.pyi new file mode 100644 index 000000000..96f095cd9 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ds18x20.pyi @@ -0,0 +1,18 @@ +""" +Module: 'ds18x20' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def const(*args, **kwargs) -> Incomplete: ... + +class DS18X20: + def read_scratch(self, *args, **kwargs) -> Incomplete: ... + def read_temp(self, *args, **kwargs) -> Incomplete: ... + def write_scratch(self, *args, **kwargs) -> Incomplete: ... + def convert_temp(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/errno.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/errno.pyi new file mode 100644 index 000000000..09ceffd3f --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/errno.pyi @@ -0,0 +1,33 @@ +""" +Module: 'errno' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +ENOBUFS: Final[int] = 105 +ENODEV: Final[int] = 19 +ENOENT: Final[int] = 2 +EISDIR: Final[int] = 21 +EIO: Final[int] = 5 +EINVAL: Final[int] = 22 +EPERM: Final[int] = 1 +ETIMEDOUT: Final[int] = 116 +ENOMEM: Final[int] = 12 +EOPNOTSUPP: Final[int] = 95 +ENOTCONN: Final[int] = 128 +errorcode: dict = {} +EAGAIN: Final[int] = 11 +EALREADY: Final[int] = 120 +EBADF: Final[int] = 9 +EADDRINUSE: Final[int] = 112 +EACCES: Final[int] = 13 +EINPROGRESS: Final[int] = 119 +EEXIST: Final[int] = 17 +EHOSTUNREACH: Final[int] = 118 +ECONNABORTED: Final[int] = 113 +ECONNRESET: Final[int] = 104 +ECONNREFUSED: Final[int] = 111 diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/framebuf.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/framebuf.pyi new file mode 100644 index 000000000..0dd861aea --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/framebuf.pyi @@ -0,0 +1,35 @@ +""" +Module: 'framebuf' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +MONO_HMSB: Final[int] = 4 +MONO_HLSB: Final[int] = 3 +RGB565: Final[int] = 1 +MONO_VLSB: Final[int] = 0 +MVLSB: Final[int] = 0 +GS2_HMSB: Final[int] = 5 +GS8: Final[int] = 6 +GS4_HMSB: Final[int] = 2 + +def FrameBuffer1(*args, **kwargs) -> Incomplete: ... + +class FrameBuffer: + def poly(self, *args, **kwargs) -> Incomplete: ... + def vline(self, *args, **kwargs) -> Incomplete: ... + def pixel(self, *args, **kwargs) -> Incomplete: ... + def text(self, *args, **kwargs) -> Incomplete: ... + def rect(self, *args, **kwargs) -> Incomplete: ... + def scroll(self, *args, **kwargs) -> Incomplete: ... + def ellipse(self, *args, **kwargs) -> Incomplete: ... + def line(self, *args, **kwargs) -> Incomplete: ... + def blit(self, *args, **kwargs) -> Incomplete: ... + def hline(self, *args, **kwargs) -> Incomplete: ... + def fill(self, *args, **kwargs) -> Incomplete: ... + def fill_rect(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/gc.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/gc.pyi new file mode 100644 index 000000000..cc00167db --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/gc.pyi @@ -0,0 +1,16 @@ +""" +Module: 'gc' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def mem_alloc(*args, **kwargs) -> Incomplete: ... +def isenabled(*args, **kwargs) -> Incomplete: ... +def mem_free(*args, **kwargs) -> Incomplete: ... +def threshold(*args, **kwargs) -> Incomplete: ... +def collect(*args, **kwargs) -> Incomplete: ... +def enable(*args, **kwargs) -> Incomplete: ... +def disable(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/hashlib.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/hashlib.pyi new file mode 100644 index 000000000..6aa2ec9b9 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/hashlib.pyi @@ -0,0 +1,13 @@ +""" +Module: 'hashlib' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class sha256: + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/heapq.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/heapq.pyi new file mode 100644 index 000000000..ebffff6d4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/heapq.pyi @@ -0,0 +1,12 @@ +""" +Module: 'heapq' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def heappop(*args, **kwargs) -> Incomplete: ... +def heappush(*args, **kwargs) -> Incomplete: ... +def heapify(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/io.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/io.pyi new file mode 100644 index 000000000..dfaa0a5ec --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/io.pyi @@ -0,0 +1,37 @@ +""" +Module: 'io' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def open(*args, **kwargs) -> Incomplete: ... + +class IOBase: + def __init__(self, *argv, **kwargs) -> None: ... + +class StringIO: + def write(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def getvalue(self, *args, **kwargs) -> Incomplete: ... + def seek(self, *args, **kwargs) -> Incomplete: ... + def tell(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class BytesIO: + def write(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def getvalue(self, *args, **kwargs) -> Incomplete: ... + def seek(self, *args, **kwargs) -> Incomplete: ... + def tell(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/json.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/json.pyi new file mode 100644 index 000000000..c17e80721 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/json.pyi @@ -0,0 +1,13 @@ +""" +Module: 'json' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def loads(*args, **kwargs) -> Incomplete: ... +def load(*args, **kwargs) -> Incomplete: ... +def dumps(*args, **kwargs) -> Incomplete: ... +def dump(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/machine.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/machine.pyi new file mode 100644 index 000000000..ece48a26c --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/machine.pyi @@ -0,0 +1,304 @@ +""" +Module: 'machine' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +SOFT_RESET: Final[int] = 5 +PWRON_RESET: Final[int] = 1 +WDT_RESET: Final[int] = 3 + +def unique_id(*args, **kwargs) -> Incomplete: ... +def disable_irq(*args, **kwargs) -> Incomplete: ... +def dht_readinto(*args, **kwargs) -> Incomplete: ... +def bitstream(*args, **kwargs) -> Incomplete: ... +def bootloader(*args, **kwargs) -> Incomplete: ... +def deepsleep(*args, **kwargs) -> Incomplete: ... +def enable_irq(*args, **kwargs) -> Incomplete: ... +def reset_cause(*args, **kwargs) -> Incomplete: ... +def soft_reset(*args, **kwargs) -> Incomplete: ... +def time_pulse_us(*args, **kwargs) -> Incomplete: ... +def reset(*args, **kwargs) -> Incomplete: ... +def freq(*args, **kwargs) -> Incomplete: ... +def idle(*args, **kwargs) -> Incomplete: ... +def lightsleep(*args, **kwargs) -> Incomplete: ... + +mem8: Incomplete ## = <8-bit memory> +mem32: Incomplete ## = <32-bit memory> +mem16: Incomplete ## = <16-bit memory> + +class LED: + def on(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class WDT: + def timeout_ms(self, *args, **kwargs) -> Incomplete: ... + def feed(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2S: + RX: Final[int] = 0 + MONO: Final[int] = 0 + STEREO: Final[int] = 1 + TX: Final[int] = 1 + def shift(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class ADC: + def read_uv(self, *args, **kwargs) -> Incomplete: ... + def read_u16(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2C: + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2CTarget: + IRQ_END_READ: Final[int] = 16 + IRQ_ADDR_MATCH_WRITE: Final[int] = 2 + IRQ_END_WRITE: Final[int] = 32 + IRQ_READ_REQ: Final[int] = 4 + IRQ_ADDR_MATCH_READ: Final[int] = 1 + IRQ_WRITE_REQ: Final[int] = 8 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SoftI2C: + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SoftSPI: + LSB: Final[int] = 1 + MSB: Final[int] = 0 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Timer: + PERIODIC: Final[int] = 2 + ONE_SHOT: Final[int] = 1 + def init(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class UART: + INV_TX: Final[int] = 1 + INV_RX: Final[int] = 2 + CTS: Final[int] = 2 + IRQ_RXIDLE: Final[int] = 1 + IRQ_TXIDLE: Final[int] = 2 + RTS: Final[int] = 1 + def irq(self, *args, **kwargs) -> Incomplete: ... + def sendbreak(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def txdone(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def any(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class PWM: + def duty_u16(self, *args, **kwargs) -> Incomplete: ... + def freq(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def duty_ns(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Signal: + def off(self, *args, **kwargs) -> Incomplete: ... + def on(self, *args, **kwargs) -> Incomplete: ... + def value(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Pin: + OPEN_DRAIN: Final[int] = 2 + IRQ_RISING: Final[int] = 1 + IRQ_FALLING: Final[int] = 2 + IN: Final[int] = 0 + PULL_UP_22K: Final[int] = 3 + OUT: Final[int] = 1 + PULL_UP: Final[int] = 2 + PULL_HOLD: Final[int] = 5 + PULL_DOWN: Final[int] = 0 + DRIVE_2: Final[int] = 3 + DRIVE_1: Final[int] = 2 + DRIVE_0: Final[int] = 1 + PULL_UP_47K: Final[int] = 1 + DRIVE_OFF: Final[int] = 0 + DRIVE_3: Final[int] = 4 + DRIVE_6: Final[int] = 7 + DRIVE_5: Final[int] = 6 + DRIVE_4: Final[int] = 5 + def low(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def on(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def value(self, *args, **kwargs) -> Incomplete: ... + def high(self, *args, **kwargs) -> Incomplete: ... + + class cpu: + GPIO_SD_00: Pin ## = Pin(GPIO_SD_00) + GPIO_AD_14: Pin ## = Pin(GPIO_AD_14) + GPIO_AD_13: Pin ## = Pin(GPIO_AD_13) + GPIO_SD_01: Pin ## = Pin(GPIO_SD_01) + GPIO_SD_02: Pin ## = Pin(GPIO_SD_02) + PMIC_ON_REQ: Pin ## = Pin(PMIC_ON_REQ) + GPIO_AD_09: Pin ## = Pin(GPIO_AD_09) + GPIO_AD_08: Pin ## = Pin(GPIO_AD_08) + GPIO_AD_12: Pin ## = Pin(GPIO_AD_12) + GPIO_AD_10: Pin ## = Pin(GPIO_AD_10) + GPIO_AD_11: Pin ## = Pin(GPIO_AD_11) + GPIO_SD_11: Pin ## = Pin(GPIO_SD_11) + GPIO_SD_10: Pin ## = Pin(GPIO_SD_10) + GPIO_SD_09: Pin ## = Pin(GPIO_SD_09) + GPIO_SD_12: Pin ## = Pin(GPIO_SD_12) + GPIO_SD_13: Pin ## = Pin(GPIO_SD_13) + GPIO_SD_03: Pin ## = Pin(GPIO_SD_03) + GPIO_SD_05: Pin ## = Pin(GPIO_SD_05) + GPIO_SD_04: Pin ## = Pin(GPIO_SD_04) + GPIO_SD_08: Pin ## = Pin(GPIO_SD_08) + GPIO_SD_06: Pin ## = Pin(GPIO_SD_06) + GPIO_SD_07: Pin ## = Pin(GPIO_SD_07) + GPIO_07: Pin ## = Pin(GPIO_07) + GPIO_06: Pin ## = Pin(GPIO_06) + GPIO_05: Pin ## = Pin(GPIO_05) + GPIO_08: Pin ## = Pin(GPIO_08) + GPIO_09: Pin ## = Pin(GPIO_09) + GPIO_AD_07: Pin ## = Pin(GPIO_AD_07) + GPIO_01: Pin ## = Pin(GPIO_01) + GPIO_00: Pin ## = Pin(GPIO_00) + GPIO_04: Pin ## = Pin(GPIO_04) + GPIO_02: Pin ## = Pin(GPIO_02) + GPIO_03: Pin ## = Pin(GPIO_03) + GPIO_AD_04: Pin ## = Pin(GPIO_AD_04) + GPIO_AD_03: Pin ## = Pin(GPIO_AD_03) + GPIO_AD_02: Pin ## = Pin(GPIO_AD_02) + GPIO_AD_05: Pin ## = Pin(GPIO_AD_05) + GPIO_AD_06: Pin ## = Pin(GPIO_AD_06) + GPIO_10: Pin ## = Pin(GPIO_10) + GPIO_12: Pin ## = Pin(GPIO_12) + GPIO_11: Pin ## = Pin(GPIO_11) + GPIO_AD_01: Pin ## = Pin(GPIO_AD_01) + GPIO_13: Pin ## = Pin(GPIO_13) + GPIO_AD_00: Pin ## = Pin(GPIO_AD_00) + def __init__(self, *argv, **kwargs) -> None: ... + + class board: + LED_GREEN: Pin ## = Pin(GPIO_11) + ENC_B: Pin ## = Pin(GPIO_AD_06) + PWM_AT: Pin ## = Pin(GPIO_02) + MCK: Pin ## = Pin(GPIO_08) + PWM_AB: Pin ## = Pin(GPIO_01) + D7: Pin ## = Pin(GPIO_AD_02) + D6: Pin ## = Pin(GPIO_AD_01) + ENC_A: Pin ## = Pin(GPIO_AD_05) + D8: Pin ## = Pin(GPIO_SD_02) + D9: Pin ## = Pin(GPIO_03) + D5: Pin ## = Pin(GPIO_01) + SD_TX: Pin ## = Pin(GPIO_04) + SD_RX: Pin ## = Pin(GPIO_03) + PWM_BB: Pin ## = Pin(GPIO_03) + VOLT_DCB: Pin ## = Pin(GPIO_AD_09) + WS_RX: Pin ## = Pin(GPIO_02) + PWM_CB: Pin ## = Pin(GPIO_05) + PWM_BT: Pin ## = Pin(GPIO_04) + SCK_TX: Pin ## = Pin(GPIO_06) + PWM_CT: Pin ## = Pin(GPIO_06) + SCK_RX: Pin ## = Pin(GPIO_01) + WS_TX: Pin ## = Pin(GPIO_07) + CUR_A: Pin ## = Pin(GPIO_AD_01) + A5: Pin ## = Pin(GPIO_AD_02) + CUR_DCB: Pin ## = Pin(GPIO_AD_10) + CUR_B: Pin ## = Pin(GPIO_AD_02) + CUR_C: Pin ## = Pin(GPIO_AD_07) + A1: Pin ## = Pin(GPIO_AD_09) + A0: Pin ## = Pin(GPIO_AD_07) + A4: Pin ## = Pin(GPIO_AD_01) + A2: Pin ## = Pin(GPIO_AD_10) + A3: Pin ## = Pin(GPIO_AD_14) + D4: Pin ## = Pin(GPIO_08) + D15: Pin ## = Pin(GPIO_02) + D14: Pin ## = Pin(GPIO_01) + D0: Pin ## = Pin(GPIO_09) + D2: Pin ## = Pin(GPIO_AD_05) + D3: Pin ## = Pin(GPIO_AD_06) + D10: Pin ## = Pin(GPIO_AD_05) + D1: Pin ## = Pin(GPIO_10) + D13: Pin ## = Pin(GPIO_AD_06) + D11: Pin ## = Pin(GPIO_AD_04) + D12: Pin ## = Pin(GPIO_AD_03) + def __init__(self, *argv, **kwargs) -> None: ... + + def __init__(self, *argv, **kwargs) -> None: ... + +class RTC: + ALARM0: Final[int] = 0 + def irq(self, *args, **kwargs) -> Incomplete: ... + def cancel(self, *args, **kwargs) -> Incomplete: ... + def datetime(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def calibration(self, *args, **kwargs) -> Incomplete: ... + def alarm(self, *args, **kwargs) -> Incomplete: ... + def alarm_cancel(self, *args, **kwargs) -> Incomplete: ... + def alarm_left(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SPI: + LSB: Final[int] = 1 + MSB: Final[int] = 0 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/math.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/math.pyi new file mode 100644 index 000000000..6820aa199 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/math.pyi @@ -0,0 +1,55 @@ +""" +Module: 'math' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +inf: float = inf +nan: float = nan +pi: float = 3.1415928 +e: float = 2.7182818 +tau: float = 6.2831856 + +def ldexp(*args, **kwargs) -> Incomplete: ... +def lgamma(*args, **kwargs) -> Incomplete: ... +def trunc(*args, **kwargs) -> Incomplete: ... +def isclose(*args, **kwargs) -> Incomplete: ... +def gamma(*args, **kwargs) -> Incomplete: ... +def isnan(*args, **kwargs) -> Incomplete: ... +def isfinite(*args, **kwargs) -> Incomplete: ... +def isinf(*args, **kwargs) -> Incomplete: ... +def sqrt(*args, **kwargs) -> Incomplete: ... +def sinh(*args, **kwargs) -> Incomplete: ... +def log(*args, **kwargs) -> Incomplete: ... +def tan(*args, **kwargs) -> Incomplete: ... +def tanh(*args, **kwargs) -> Incomplete: ... +def log2(*args, **kwargs) -> Incomplete: ... +def log10(*args, **kwargs) -> Incomplete: ... +def sin(*args, **kwargs) -> Incomplete: ... +def modf(*args, **kwargs) -> Incomplete: ... +def radians(*args, **kwargs) -> Incomplete: ... +def atanh(*args, **kwargs) -> Incomplete: ... +def atan2(*args, **kwargs) -> Incomplete: ... +def atan(*args, **kwargs) -> Incomplete: ... +def ceil(*args, **kwargs) -> Incomplete: ... +def copysign(*args, **kwargs) -> Incomplete: ... +def frexp(*args, **kwargs) -> Incomplete: ... +def acos(*args, **kwargs) -> Incomplete: ... +def pow(*args, **kwargs) -> Incomplete: ... +def asinh(*args, **kwargs) -> Incomplete: ... +def acosh(*args, **kwargs) -> Incomplete: ... +def asin(*args, **kwargs) -> Incomplete: ... +def factorial(*args, **kwargs) -> Incomplete: ... +def fabs(*args, **kwargs) -> Incomplete: ... +def expm1(*args, **kwargs) -> Incomplete: ... +def floor(*args, **kwargs) -> Incomplete: ... +def fmod(*args, **kwargs) -> Incomplete: ... +def cos(*args, **kwargs) -> Incomplete: ... +def degrees(*args, **kwargs) -> Incomplete: ... +def cosh(*args, **kwargs) -> Incomplete: ... +def exp(*args, **kwargs) -> Incomplete: ... +def erf(*args, **kwargs) -> Incomplete: ... +def erfc(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/micropython.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/micropython.pyi new file mode 100644 index 000000000..722164093 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/micropython.pyi @@ -0,0 +1,28 @@ +""" +Module: 'micropython' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def opt_level(*args, **kwargs) -> Incomplete: ... +def mem_info(*args, **kwargs) -> Incomplete: ... +def kbd_intr(*args, **kwargs) -> Incomplete: ... +def qstr_info(*args, **kwargs) -> Incomplete: ... +def schedule(*args, **kwargs) -> Incomplete: ... +def stack_use(*args, **kwargs) -> Incomplete: ... +def heap_unlock(*args, **kwargs) -> Incomplete: ... +def const(*args, **kwargs) -> Incomplete: ... +def heap_lock(*args, **kwargs) -> Incomplete: ... +def alloc_emergency_exception_buf(*args, **kwargs) -> Incomplete: ... + +class RingIO: + def readinto(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def any(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/mimxrt.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/mimxrt.pyi new file mode 100644 index 000000000..27ed8e301 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/mimxrt.pyi @@ -0,0 +1,14 @@ +""" +Module: 'mimxrt' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class Flash: + def readblocks(self, *args, **kwargs) -> Incomplete: ... + def writeblocks(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/modules.json b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/modules.json new file mode 100644 index 000000000..edfe28f22 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/modules.json @@ -0,0 +1,69 @@ +{"firmware": {"variant": "", "build": "", "arch": "armv7emsp", "port": "mimxrt", "board": "MIMXRT1010_EVK", "board_id": "MIMXRT1010_EVK", "mpy": "v6.3", "ver": "1.26.1", "family": "micropython", "cpu": "MIMXRT1011DAE5A", "version": "1.26.1"}, +"stubber": {"version": "v1.26.3"}, "stubtype": "firmware", +"modules" :[ +{"module": "_asyncio", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_asyncio.pyi"}, +{"module": "_onewire", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/_onewire.pyi"}, +{"module": "array", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/array.pyi"}, +{"module": "asyncio.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/__init__.pyi"}, +{"module": "asyncio.core", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/core.pyi"}, +{"module": "asyncio.event", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/event.pyi"}, +{"module": "asyncio.funcs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/funcs.pyi"}, +{"module": "asyncio.lock", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/lock.pyi"}, +{"module": "asyncio.stream", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/asyncio/stream.pyi"}, +{"module": "binascii", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/binascii.pyi"}, +{"module": "builtins", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/builtins.pyi"}, +{"module": "cmath", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/cmath.pyi"}, +{"module": "collections", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/collections.pyi"}, +{"module": "deflate", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/deflate.pyi"}, +{"module": "dht", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/dht.pyi"}, +{"module": "ds18x20", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ds18x20.pyi"}, +{"module": "errno", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/errno.pyi"}, +{"module": "framebuf", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/framebuf.pyi"}, +{"module": "gc", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/gc.pyi"}, +{"module": "hashlib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/hashlib.pyi"}, +{"module": "heapq", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/heapq.pyi"}, +{"module": "io", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/io.pyi"}, +{"module": "json", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/json.pyi"}, +{"module": "machine", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/machine.pyi"}, +{"module": "math", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/math.pyi"}, +{"module": "micropython", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/micropython.pyi"}, +{"module": "mimxrt", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/mimxrt.pyi"}, +{"module": "network", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/network.pyi"}, +{"module": "onewire", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/onewire.pyi"}, +{"module": "os", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/os.pyi"}, +{"module": "platform", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/platform.pyi"}, +{"module": "random", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/random.pyi"}, +{"module": "select", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/select.pyi"}, +{"module": "socket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/socket.pyi"}, +{"module": "struct", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/struct.pyi"}, +{"module": "sys", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/sys.pyi"}, +{"module": "time", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/time.pyi"}, +{"module": "uarray", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uarray.pyi"}, +{"module": "uasyncio.__init__", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/__init__.pyi"}, +{"module": "uasyncio.core", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/core.pyi"}, +{"module": "uasyncio.event", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/event.pyi"}, +{"module": "uasyncio.funcs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/funcs.pyi"}, +{"module": "uasyncio.lock", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/lock.pyi"}, +{"module": "uasyncio.stream", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/stream.pyi"}, +{"module": "ubinascii", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ubinascii.pyi"}, +{"module": "ucollections", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ucollections.pyi"}, +{"module": "uctypes", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uctypes.pyi"}, +{"module": "uerrno", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uerrno.pyi"}, +{"module": "uhashlib", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uhashlib.pyi"}, +{"module": "uheapq", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uheapq.pyi"}, +{"module": "uio", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uio.pyi"}, +{"module": "ujson", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ujson.pyi"}, +{"module": "umachine", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/umachine.pyi"}, +{"module": "uos", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uos.pyi"}, +{"module": "uplatform", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uplatform.pyi"}, +{"module": "urandom", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/urandom.pyi"}, +{"module": "ure", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ure.pyi"}, +{"module": "usb.device", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device.pyi"}, +{"module": "usb.device.cdc", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device/cdc.pyi"}, +{"module": "uselect", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uselect.pyi"}, +{"module": "usocket", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usocket.pyi"}, +{"module": "ustruct", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ustruct.pyi"}, +{"module": "usys", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usys.pyi"}, +{"module": "utime", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/utime.pyi"}, +{"module": "vfs", "file": "/remote/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/vfs.pyi"} +]} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/network.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/network.pyi new file mode 100644 index 000000000..a9ca8df5a --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/network.pyi @@ -0,0 +1,16 @@ +""" +Module: 'network' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +STA_IF: Final[int] = 0 +AP_IF: Final[int] = 1 + +def hostname(*args, **kwargs) -> Incomplete: ... +def route(*args, **kwargs) -> Incomplete: ... +def country(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/onewire.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/onewire.pyi new file mode 100644 index 000000000..0f342b252 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/onewire.pyi @@ -0,0 +1,28 @@ +""" +Module: 'onewire' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SKIP_ROM: Final[int] = 204 + SEARCH_ROM: Final[int] = 240 + MATCH_ROM: Final[int] = 85 + def select_rom(self, *args, **kwargs) -> Incomplete: ... + def writebit(self, *args, **kwargs) -> Incomplete: ... + def writebyte(self, *args, **kwargs) -> Incomplete: ... + def _search_rom(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def crc8(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def reset(self, *args, **kwargs) -> Incomplete: ... + def readbit(self, *args, **kwargs) -> Incomplete: ... + def readbyte(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/os.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/os.pyi new file mode 100644 index 000000000..b7460e2bb --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/os.pyi @@ -0,0 +1,61 @@ +""" +Module: 'os' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +sep: str = "/" + +def rmdir(*args, **kwargs) -> Incomplete: ... +def stat(*args, **kwargs) -> Incomplete: ... +def urandom(*args, **kwargs) -> Incomplete: ... +def rename(*args, **kwargs) -> Incomplete: ... +def mount(*args, **kwargs) -> Incomplete: ... +def uname(*args, **kwargs) -> Incomplete: ... +def unlink(*args, **kwargs) -> Incomplete: ... +def statvfs(*args, **kwargs) -> Incomplete: ... +def umount(*args, **kwargs) -> Incomplete: ... +def sync(*args, **kwargs) -> Incomplete: ... +def mkdir(*args, **kwargs) -> Incomplete: ... +def dupterm(*args, **kwargs) -> Incomplete: ... +def chdir(*args, **kwargs) -> Incomplete: ... +def remove(*args, **kwargs) -> Incomplete: ... +def dupterm_notify(*args, **kwargs) -> Incomplete: ... +def listdir(*args, **kwargs) -> Incomplete: ... +def ilistdir(*args, **kwargs) -> Incomplete: ... +def getcwd(*args, **kwargs) -> Incomplete: ... + +class VfsFat: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class VfsLfs2: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/platform.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/platform.pyi new file mode 100644 index 000000000..30300f129 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/platform.pyi @@ -0,0 +1,12 @@ +""" +Module: 'platform' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def platform(*args, **kwargs) -> Incomplete: ... +def python_compiler(*args, **kwargs) -> Incomplete: ... +def libc_ver(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/random.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/random.pyi new file mode 100644 index 000000000..301ecfe33 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/random.pyi @@ -0,0 +1,16 @@ +""" +Module: 'random' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def randrange(*args, **kwargs) -> Incomplete: ... +def random(*args, **kwargs) -> Incomplete: ... +def seed(*args, **kwargs) -> Incomplete: ... +def uniform(*args, **kwargs) -> Incomplete: ... +def choice(*args, **kwargs) -> Incomplete: ... +def randint(*args, **kwargs) -> Incomplete: ... +def getrandbits(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/select.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/select.pyi new file mode 100644 index 000000000..7c0c4f399 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/select.pyi @@ -0,0 +1,17 @@ +""" +Module: 'select' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +POLLOUT: Final[int] = 4 +POLLIN: Final[int] = 1 +POLLHUP: Final[int] = 16 +POLLERR: Final[int] = 8 + +def select(*args, **kwargs) -> Incomplete: ... +def poll(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/socket.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/socket.pyi new file mode 100644 index 000000000..112bab894 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/socket.pyi @@ -0,0 +1,44 @@ +""" +Module: 'socket' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +SO_KEEPALIVE: Final[int] = 8 +SO_BROADCAST: Final[int] = 32 +SOL_SOCKET: Final[int] = 4095 +SO_RCVTIMEO: Final[int] = 4102 +SO_REUSEADDR: Final[int] = 4 +SO_SNDTIMEO: Final[int] = 4101 +AF_INET6: Final[int] = 10 +AF_INET: Final[int] = 2 +SOCK_STREAM: Final[int] = 1 +SOCK_DGRAM: Final[int] = 2 +SOCK_RAW: Final[int] = 3 + +def getaddrinfo(*args, **kwargs) -> Incomplete: ... + +class socket: + def recvfrom(self, *args, **kwargs) -> Incomplete: ... + def recv(self, *args, **kwargs) -> Incomplete: ... + def makefile(self, *args, **kwargs) -> Incomplete: ... + def listen(self, *args, **kwargs) -> Incomplete: ... + def settimeout(self, *args, **kwargs) -> Incomplete: ... + def sendall(self, *args, **kwargs) -> Incomplete: ... + def setsockopt(self, *args, **kwargs) -> Incomplete: ... + def setblocking(self, *args, **kwargs) -> Incomplete: ... + def sendto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def connect(self, *args, **kwargs) -> Incomplete: ... + def send(self, *args, **kwargs) -> Incomplete: ... + def bind(self, *args, **kwargs) -> Incomplete: ... + def accept(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/struct.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/struct.pyi new file mode 100644 index 000000000..762ec67b6 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/struct.pyi @@ -0,0 +1,14 @@ +""" +Module: 'struct' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def pack_into(*args, **kwargs) -> Incomplete: ... +def unpack(*args, **kwargs) -> Incomplete: ... +def unpack_from(*args, **kwargs) -> Incomplete: ... +def pack(*args, **kwargs) -> Incomplete: ... +def calcsize(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/sys.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/sys.pyi new file mode 100644 index 000000000..d7aaa0435 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/sys.pyi @@ -0,0 +1,27 @@ +""" +Module: 'sys' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +platform: str = "mimxrt" +version_info: tuple = () +path: list = [] +version: str = "3.4.0; MicroPython v1.26.1 on 2025-09-11" +ps1: str = ">>> " +ps2: str = "... " +byteorder: str = "little" +modules: dict = {} +argv: list = [] +implementation: tuple = () +maxsize: int = 2147483647 + +def print_exception(*args, **kwargs) -> Incomplete: ... +def exit(*args, **kwargs) -> Incomplete: ... + +stderr: Incomplete ## = +stdout: Incomplete ## = +stdin: Incomplete ## = diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/time.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/time.pyi new file mode 100644 index 000000000..eaefc46c2 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/time.pyi @@ -0,0 +1,22 @@ +""" +Module: 'time' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def ticks_diff(*args, **kwargs) -> Incomplete: ... +def ticks_add(*args, **kwargs) -> Incomplete: ... +def ticks_cpu(*args, **kwargs) -> Incomplete: ... +def time(*args, **kwargs) -> Incomplete: ... +def ticks_ms(*args, **kwargs) -> Incomplete: ... +def ticks_us(*args, **kwargs) -> Incomplete: ... +def time_ns(*args, **kwargs) -> Incomplete: ... +def localtime(*args, **kwargs) -> Incomplete: ... +def sleep_us(*args, **kwargs) -> Incomplete: ... +def gmtime(*args, **kwargs) -> Incomplete: ... +def sleep_ms(*args, **kwargs) -> Incomplete: ... +def mktime(*args, **kwargs) -> Incomplete: ... +def sleep(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uarray.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uarray.pyi new file mode 100644 index 000000000..c59c40c9c --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uarray.pyi @@ -0,0 +1,14 @@ +""" +Module: 'uarray' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +class array: + def extend(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/__init__.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/__init__.pyi new file mode 100644 index 000000000..531edd0ef --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/__init__.pyi @@ -0,0 +1,278 @@ +""" +Module: 'uasyncio.__init__' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +_attrs: dict = {} +def current_task(*args, **kwargs) -> Incomplete: + ... + +def get_event_loop(*args, **kwargs) -> Incomplete: + ... + +def create_task(*args, **kwargs) -> Incomplete: + ... + +def ticks_diff(*args, **kwargs) -> Incomplete: + ... + +def new_event_loop(*args, **kwargs) -> Incomplete: + ... + +def ticks(*args, **kwargs) -> Incomplete: + ... + +def run_until_complete(*args, **kwargs) -> Incomplete: + ... + +def run(*args, **kwargs) -> Incomplete: + ... + +def wait_for_ms(*args, **kwargs) -> Incomplete: + ... + +def sleep_ms(*args, **kwargs) -> Incomplete: + ... + +def ticks_add(*args, **kwargs) -> Incomplete: + ... + +def sleep(*args, **kwargs) -> Incomplete: + ... + + +class TaskQueue(): + def push(self, *args, **kwargs) -> Incomplete: + ... + + def peek(self, *args, **kwargs) -> Incomplete: + ... + + def remove(self, *args, **kwargs) -> Incomplete: + ... + + def pop(self, *args, **kwargs) -> Incomplete: + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + +def open_connection(*args, **kwargs) -> Generator: ## = + ... + +cur_task: Incomplete ## = None +def gather(*args, **kwargs) -> Generator: ## = + ... + + +class Task(): + def __init__(self, *argv, **kwargs) -> None: + ... + +def wait_for(*args, **kwargs) -> Generator: ## = + ... + + +class CancelledError(Exception): + ... +def start_server(*args, **kwargs) -> Generator: ## = + ... + + +class Lock(): + def locked(self, *args, **kwargs) -> Incomplete: + ... + + def release(self, *args, **kwargs) -> Incomplete: + ... + + def acquire(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class StreamWriter(): + def write(self, *args, **kwargs) -> Incomplete: + ... + + def get_extra_info(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def awritestr(*args, **kwargs) -> Generator: ## = + ... + + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + + def drain(*args, **kwargs) -> Generator: ## = + ... + + def readexactly(*args, **kwargs) -> Generator: ## = + ... + + def readinto(*args, **kwargs) -> Generator: ## = + ... + + def read(*args, **kwargs) -> Generator: ## = + ... + + def awrite(*args, **kwargs) -> Generator: ## = + ... + + def readline(*args, **kwargs) -> Generator: ## = + ... + + def aclose(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class StreamReader(): + def write(self, *args, **kwargs) -> Incomplete: + ... + + def get_extra_info(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def awritestr(*args, **kwargs) -> Generator: ## = + ... + + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + + def drain(*args, **kwargs) -> Generator: ## = + ... + + def readexactly(*args, **kwargs) -> Generator: ## = + ... + + def readinto(*args, **kwargs) -> Generator: ## = + ... + + def read(*args, **kwargs) -> Generator: ## = + ... + + def awrite(*args, **kwargs) -> Generator: ## = + ... + + def readline(*args, **kwargs) -> Generator: ## = + ... + + def aclose(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class SingletonGenerator(): + def __init__(self, *argv, **kwargs) -> None: + ... + + +class Loop(): + def get_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def default_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def set_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + def run_forever(self, *args, **kwargs) -> Incomplete: + ... + + def run_until_complete(self, *args, **kwargs) -> Incomplete: + ... + + def stop(self, *args, **kwargs) -> Incomplete: + ... + + def close(self, *args, **kwargs) -> Incomplete: + ... + + def create_task(self, *args, **kwargs) -> Incomplete: + ... + + def call_exception_handler(self, *args, **kwargs) -> Incomplete: + ... + + _exc_handler: Incomplete ## = None + def __init__(self, *argv, **kwargs) -> None: + ... + + +class Event(): + def set(self, *args, **kwargs) -> Incomplete: + ... + + def is_set(self, *args, **kwargs) -> Incomplete: + ... + + def clear(self, *args, **kwargs) -> Incomplete: + ... + + def wait(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class ThreadSafeFlag(): + def set(self, *args, **kwargs) -> Incomplete: + ... + + def ioctl(self, *args, **kwargs) -> Incomplete: + ... + + def clear(self, *args, **kwargs) -> Incomplete: + ... + + def wait(*args, **kwargs) -> Generator: ## = + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class IOQueue(): + def queue_read(self, *args, **kwargs) -> Incomplete: + ... + + def wait_io_event(self, *args, **kwargs) -> Incomplete: + ... + + def queue_write(self, *args, **kwargs) -> Incomplete: + ... + + def remove(self, *args, **kwargs) -> Incomplete: + ... + + def _enqueue(self, *args, **kwargs) -> Incomplete: + ... + + def _dequeue(self, *args, **kwargs) -> Incomplete: + ... + + def __init__(self, *argv, **kwargs) -> None: + ... + + +class TimeoutError(Exception): + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/core.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/core.pyi new file mode 100644 index 000000000..f7de447db --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/core.pyi @@ -0,0 +1,73 @@ +""" +Module: 'uasyncio.core' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +_exc_context: dict = {} + +def ticks(*args, **kwargs) -> Incomplete: ... +def create_task(*args, **kwargs) -> Incomplete: ... +def _promote_to_task(*args, **kwargs) -> Incomplete: ... +def ticks_diff(*args, **kwargs) -> Incomplete: ... +def run(*args, **kwargs) -> Incomplete: ... +def run_until_complete(*args, **kwargs) -> Incomplete: ... +def current_task(*args, **kwargs) -> Incomplete: ... +def new_event_loop(*args, **kwargs) -> Incomplete: ... +def get_event_loop(*args, **kwargs) -> Incomplete: ... +def sleep_ms(*args, **kwargs) -> Incomplete: ... +def ticks_add(*args, **kwargs) -> Incomplete: ... +def sleep(*args, **kwargs) -> Incomplete: ... + +cur_task: Incomplete ## = None +_task_queue: Incomplete ## = + +class Loop: + def get_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def default_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def set_exception_handler(self, *args, **kwargs) -> Incomplete: ... + def run_forever(self, *args, **kwargs) -> Incomplete: ... + def run_until_complete(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def create_task(self, *args, **kwargs) -> Incomplete: ... + def call_exception_handler(self, *args, **kwargs) -> Incomplete: ... + + _exc_handler: Incomplete ## = None + def __init__(self, *argv, **kwargs) -> None: ... + +class CancelledError(Exception): ... + +class TaskQueue: + def push(self, *args, **kwargs) -> Incomplete: ... + def peek(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Task: + def __init__(self, *argv, **kwargs) -> None: ... + +class TimeoutError(Exception): ... + +class IOQueue: + def queue_read(self, *args, **kwargs) -> Incomplete: ... + def wait_io_event(self, *args, **kwargs) -> Incomplete: ... + def queue_write(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def _enqueue(self, *args, **kwargs) -> Incomplete: ... + def _dequeue(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SingletonGenerator: + def __init__(self, *argv, **kwargs) -> None: ... + +def _stopper(*args, **kwargs) -> Generator: ## = + ... + +_stop_task: Incomplete ## = None +_io_queue: Incomplete ## = diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/event.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/event.pyi new file mode 100644 index 000000000..f39b6656c --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/event.pyi @@ -0,0 +1,25 @@ +""" +Module: 'uasyncio.event' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +class ThreadSafeFlag: + def set(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def wait(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Event: + def set(self, *args, **kwargs) -> Incomplete: ... + def is_set(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def wait(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/funcs.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/funcs.pyi new file mode 100644 index 000000000..f25ae0321 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/funcs.pyi @@ -0,0 +1,22 @@ +""" +Module: 'uasyncio.funcs' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +def wait_for_ms(*args, **kwargs) -> Incomplete: ... +def gather(*args, **kwargs) -> Generator: ## = + ... +def wait_for(*args, **kwargs) -> Generator: ## = + ... + +class _Remove: + def remove(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +def _run(*args, **kwargs) -> Generator: ## = + ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/lock.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/lock.pyi new file mode 100644 index 000000000..5626bad2c --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/lock.pyi @@ -0,0 +1,16 @@ +""" +Module: 'uasyncio.lock' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +class Lock: + def locked(self, *args, **kwargs) -> Incomplete: ... + def release(self, *args, **kwargs) -> Incomplete: ... + def acquire(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/stream.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/stream.pyi new file mode 100644 index 000000000..9bf75b0ac --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uasyncio/stream.pyi @@ -0,0 +1,96 @@ +""" +Module: 'uasyncio.stream' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Generator +from _typeshed import Incomplete + +def stream_awrite(*args, **kwargs) -> Generator: ## = + ... +def open_connection(*args, **kwargs) -> Generator: ## = + ... +def start_server(*args, **kwargs) -> Generator: ## = + ... + +class StreamWriter: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Server: + def close(self, *args, **kwargs) -> Incomplete: ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def _serve(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Stream: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... + +class StreamReader: + def write(self, *args, **kwargs) -> Incomplete: ... + def get_extra_info(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def awritestr(*args, **kwargs) -> Generator: ## = + ... + def wait_closed(*args, **kwargs) -> Generator: ## = + ... + def drain(*args, **kwargs) -> Generator: ## = + ... + def readexactly(*args, **kwargs) -> Generator: ## = + ... + def readinto(*args, **kwargs) -> Generator: ## = + ... + def read(*args, **kwargs) -> Generator: ## = + ... + def awrite(*args, **kwargs) -> Generator: ## = + ... + def readline(*args, **kwargs) -> Generator: ## = + ... + def aclose(*args, **kwargs) -> Generator: ## = + ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ubinascii.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ubinascii.pyi new file mode 100644 index 000000000..035476734 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ubinascii.pyi @@ -0,0 +1,15 @@ +""" +Module: 'ubinascii' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def crc32(*args, **kwargs) -> Incomplete: ... +def hexlify(*args, **kwargs) -> Incomplete: ... +def unhexlify(*args, **kwargs) -> Incomplete: ... +def b2a_base64(*args, **kwargs) -> Incomplete: ... +def a2b_base64(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ucollections.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ucollections.pyi new file mode 100644 index 000000000..733f193d2 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ucollections.pyi @@ -0,0 +1,34 @@ +""" +Module: 'ucollections' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def namedtuple(*args, **kwargs) -> Incomplete: ... + +class OrderedDict: + def popitem(self, *args, **kwargs) -> Incomplete: ... + def pop(self, *args, **kwargs) -> Incomplete: ... + def values(self, *args, **kwargs) -> Incomplete: ... + def setdefault(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def copy(self, *args, **kwargs) -> Incomplete: ... + def clear(self, *args, **kwargs) -> Incomplete: ... + def keys(self, *args, **kwargs) -> Incomplete: ... + def get(self, *args, **kwargs) -> Incomplete: ... + def items(self, *args, **kwargs) -> Incomplete: ... + @classmethod + def fromkeys(cls, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class deque: + def pop(self, *args, **kwargs) -> Incomplete: ... + def appendleft(self, *args, **kwargs) -> Incomplete: ... + def popleft(self, *args, **kwargs) -> Incomplete: ... + def extend(self, *args, **kwargs) -> Incomplete: ... + def append(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uctypes.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uctypes.pyi new file mode 100644 index 000000000..a5b4d8f3b --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uctypes.pyi @@ -0,0 +1,50 @@ +""" +Module: 'uctypes' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +VOID: Final[int] = 0 +NATIVE: Final[int] = 2 +PTR: Final[int] = 536870912 +SHORT: Final[int] = 402653184 +LONGLONG: Final[int] = 939524096 +INT8: Final[int] = 134217728 +LITTLE_ENDIAN: Final[int] = 0 +LONG: Final[int] = 671088640 +UINT: Final[int] = 536870912 +ULONG: Final[int] = 536870912 +ULONGLONG: Final[int] = 805306368 +USHORT: Final[int] = 268435456 +UINT8: Final[int] = 0 +UINT16: Final[int] = 268435456 +UINT32: Final[int] = 536870912 +UINT64: Final[int] = 805306368 +INT64: Final[int] = 939524096 +BFUINT16: Final[int] = -805306368 +BFUINT32: Final[int] = -536870912 +BFUINT8: Final[int] = -1073741824 +BFINT8: Final[int] = -939524096 +ARRAY: Final[int] = -1073741824 +BFINT16: Final[int] = -671088640 +BFINT32: Final[int] = -402653184 +BF_LEN: Final[int] = 22 +INT: Final[int] = 671088640 +INT16: Final[int] = 402653184 +INT32: Final[int] = 671088640 +FLOAT64: Final[int] = -134217728 +BF_POS: Final[int] = 17 +BIG_ENDIAN: Final[int] = 1 +FLOAT32: Final[int] = -268435456 + +def sizeof(*args, **kwargs) -> Incomplete: ... +def bytes_at(*args, **kwargs) -> Incomplete: ... +def bytearray_at(*args, **kwargs) -> Incomplete: ... +def addressof(*args, **kwargs) -> Incomplete: ... + +class struct: + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uerrno.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uerrno.pyi new file mode 100644 index 000000000..8d42c65b4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uerrno.pyi @@ -0,0 +1,33 @@ +""" +Module: 'uerrno' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +ENOBUFS: Final[int] = 105 +ENODEV: Final[int] = 19 +ENOENT: Final[int] = 2 +EISDIR: Final[int] = 21 +EIO: Final[int] = 5 +EINVAL: Final[int] = 22 +EPERM: Final[int] = 1 +ETIMEDOUT: Final[int] = 116 +ENOMEM: Final[int] = 12 +EOPNOTSUPP: Final[int] = 95 +ENOTCONN: Final[int] = 128 +errorcode: dict = {} +EAGAIN: Final[int] = 11 +EALREADY: Final[int] = 120 +EBADF: Final[int] = 9 +EADDRINUSE: Final[int] = 112 +EACCES: Final[int] = 13 +EINPROGRESS: Final[int] = 119 +EEXIST: Final[int] = 17 +EHOSTUNREACH: Final[int] = 118 +ECONNABORTED: Final[int] = 113 +ECONNRESET: Final[int] = 104 +ECONNREFUSED: Final[int] = 111 diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uhashlib.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uhashlib.pyi new file mode 100644 index 000000000..1fe45106b --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uhashlib.pyi @@ -0,0 +1,14 @@ +""" +Module: 'uhashlib' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +class sha256: + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uheapq.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uheapq.pyi new file mode 100644 index 000000000..9fd339b22 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uheapq.pyi @@ -0,0 +1,13 @@ +""" +Module: 'uheapq' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def heappop(*args, **kwargs) -> Incomplete: ... +def heappush(*args, **kwargs) -> Incomplete: ... +def heapify(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uio.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uio.pyi new file mode 100644 index 000000000..8d45e0067 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uio.pyi @@ -0,0 +1,38 @@ +""" +Module: 'uio' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def open(*args, **kwargs) -> Incomplete: ... + +class IOBase: + def __init__(self, *argv, **kwargs) -> None: ... + +class StringIO: + def write(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def getvalue(self, *args, **kwargs) -> Incomplete: ... + def seek(self, *args, **kwargs) -> Incomplete: ... + def tell(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class BytesIO: + def write(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def getvalue(self, *args, **kwargs) -> Incomplete: ... + def seek(self, *args, **kwargs) -> Incomplete: ... + def tell(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ujson.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ujson.pyi new file mode 100644 index 000000000..3cecdf251 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ujson.pyi @@ -0,0 +1,14 @@ +""" +Module: 'ujson' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def loads(*args, **kwargs) -> Incomplete: ... +def load(*args, **kwargs) -> Incomplete: ... +def dumps(*args, **kwargs) -> Incomplete: ... +def dump(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/umachine.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/umachine.pyi new file mode 100644 index 000000000..0acbe610d --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/umachine.pyi @@ -0,0 +1,304 @@ +""" +Module: 'umachine' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +SOFT_RESET: Final[int] = 5 +PWRON_RESET: Final[int] = 1 +WDT_RESET: Final[int] = 3 + +def unique_id(*args, **kwargs) -> Incomplete: ... +def disable_irq(*args, **kwargs) -> Incomplete: ... +def dht_readinto(*args, **kwargs) -> Incomplete: ... +def bitstream(*args, **kwargs) -> Incomplete: ... +def bootloader(*args, **kwargs) -> Incomplete: ... +def deepsleep(*args, **kwargs) -> Incomplete: ... +def enable_irq(*args, **kwargs) -> Incomplete: ... +def reset_cause(*args, **kwargs) -> Incomplete: ... +def soft_reset(*args, **kwargs) -> Incomplete: ... +def time_pulse_us(*args, **kwargs) -> Incomplete: ... +def reset(*args, **kwargs) -> Incomplete: ... +def freq(*args, **kwargs) -> Incomplete: ... +def idle(*args, **kwargs) -> Incomplete: ... +def lightsleep(*args, **kwargs) -> Incomplete: ... + +mem8: Incomplete ## = <8-bit memory> +mem32: Incomplete ## = <32-bit memory> +mem16: Incomplete ## = <16-bit memory> + +class LED: + def on(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class WDT: + def timeout_ms(self, *args, **kwargs) -> Incomplete: ... + def feed(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2S: + RX: Final[int] = 0 + MONO: Final[int] = 0 + STEREO: Final[int] = 1 + TX: Final[int] = 1 + def shift(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class ADC: + def read_uv(self, *args, **kwargs) -> Incomplete: ... + def read_u16(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2C: + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class I2CTarget: + IRQ_END_READ: Final[int] = 16 + IRQ_ADDR_MATCH_WRITE: Final[int] = 2 + IRQ_END_WRITE: Final[int] = 32 + IRQ_READ_REQ: Final[int] = 4 + IRQ_ADDR_MATCH_READ: Final[int] = 1 + IRQ_WRITE_REQ: Final[int] = 8 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SoftI2C: + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SoftSPI: + LSB: Final[int] = 1 + MSB: Final[int] = 0 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Timer: + PERIODIC: Final[int] = 2 + ONE_SHOT: Final[int] = 1 + def init(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class UART: + INV_TX: Final[int] = 1 + INV_RX: Final[int] = 2 + CTS: Final[int] = 2 + IRQ_RXIDLE: Final[int] = 1 + IRQ_TXIDLE: Final[int] = 2 + RTS: Final[int] = 1 + def irq(self, *args, **kwargs) -> Incomplete: ... + def sendbreak(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def txdone(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def any(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class PWM: + def duty_u16(self, *args, **kwargs) -> Incomplete: ... + def freq(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def duty_ns(self, *args, **kwargs) -> Incomplete: ... + def deinit(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Signal: + def off(self, *args, **kwargs) -> Incomplete: ... + def on(self, *args, **kwargs) -> Incomplete: ... + def value(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Pin: + OPEN_DRAIN: Final[int] = 2 + IRQ_RISING: Final[int] = 1 + IRQ_FALLING: Final[int] = 2 + IN: Final[int] = 0 + PULL_UP_22K: Final[int] = 3 + OUT: Final[int] = 1 + PULL_UP: Final[int] = 2 + PULL_HOLD: Final[int] = 5 + PULL_DOWN: Final[int] = 0 + DRIVE_2: Final[int] = 3 + DRIVE_1: Final[int] = 2 + DRIVE_0: Final[int] = 1 + PULL_UP_47K: Final[int] = 1 + DRIVE_OFF: Final[int] = 0 + DRIVE_3: Final[int] = 4 + DRIVE_6: Final[int] = 7 + DRIVE_5: Final[int] = 6 + DRIVE_4: Final[int] = 5 + def low(self, *args, **kwargs) -> Incomplete: ... + def irq(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def on(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def value(self, *args, **kwargs) -> Incomplete: ... + def high(self, *args, **kwargs) -> Incomplete: ... + + class cpu: + GPIO_SD_00: Pin ## = Pin(GPIO_SD_00) + GPIO_AD_14: Pin ## = Pin(GPIO_AD_14) + GPIO_AD_13: Pin ## = Pin(GPIO_AD_13) + GPIO_SD_01: Pin ## = Pin(GPIO_SD_01) + GPIO_SD_02: Pin ## = Pin(GPIO_SD_02) + PMIC_ON_REQ: Pin ## = Pin(PMIC_ON_REQ) + GPIO_AD_09: Pin ## = Pin(GPIO_AD_09) + GPIO_AD_08: Pin ## = Pin(GPIO_AD_08) + GPIO_AD_12: Pin ## = Pin(GPIO_AD_12) + GPIO_AD_10: Pin ## = Pin(GPIO_AD_10) + GPIO_AD_11: Pin ## = Pin(GPIO_AD_11) + GPIO_SD_11: Pin ## = Pin(GPIO_SD_11) + GPIO_SD_10: Pin ## = Pin(GPIO_SD_10) + GPIO_SD_09: Pin ## = Pin(GPIO_SD_09) + GPIO_SD_12: Pin ## = Pin(GPIO_SD_12) + GPIO_SD_13: Pin ## = Pin(GPIO_SD_13) + GPIO_SD_03: Pin ## = Pin(GPIO_SD_03) + GPIO_SD_05: Pin ## = Pin(GPIO_SD_05) + GPIO_SD_04: Pin ## = Pin(GPIO_SD_04) + GPIO_SD_08: Pin ## = Pin(GPIO_SD_08) + GPIO_SD_06: Pin ## = Pin(GPIO_SD_06) + GPIO_SD_07: Pin ## = Pin(GPIO_SD_07) + GPIO_07: Pin ## = Pin(GPIO_07) + GPIO_06: Pin ## = Pin(GPIO_06) + GPIO_05: Pin ## = Pin(GPIO_05) + GPIO_08: Pin ## = Pin(GPIO_08) + GPIO_09: Pin ## = Pin(GPIO_09) + GPIO_AD_07: Pin ## = Pin(GPIO_AD_07) + GPIO_01: Pin ## = Pin(GPIO_01) + GPIO_00: Pin ## = Pin(GPIO_00) + GPIO_04: Pin ## = Pin(GPIO_04) + GPIO_02: Pin ## = Pin(GPIO_02) + GPIO_03: Pin ## = Pin(GPIO_03) + GPIO_AD_04: Pin ## = Pin(GPIO_AD_04) + GPIO_AD_03: Pin ## = Pin(GPIO_AD_03) + GPIO_AD_02: Pin ## = Pin(GPIO_AD_02) + GPIO_AD_05: Pin ## = Pin(GPIO_AD_05) + GPIO_AD_06: Pin ## = Pin(GPIO_AD_06) + GPIO_10: Pin ## = Pin(GPIO_10) + GPIO_12: Pin ## = Pin(GPIO_12) + GPIO_11: Pin ## = Pin(GPIO_11) + GPIO_AD_01: Pin ## = Pin(GPIO_AD_01) + GPIO_13: Pin ## = Pin(GPIO_13) + GPIO_AD_00: Pin ## = Pin(GPIO_AD_00) + def __init__(self, *argv, **kwargs) -> None: ... + + class board: + LED_GREEN: Pin ## = Pin(GPIO_11) + ENC_B: Pin ## = Pin(GPIO_AD_06) + PWM_AT: Pin ## = Pin(GPIO_02) + MCK: Pin ## = Pin(GPIO_08) + PWM_AB: Pin ## = Pin(GPIO_01) + D7: Pin ## = Pin(GPIO_AD_02) + D6: Pin ## = Pin(GPIO_AD_01) + ENC_A: Pin ## = Pin(GPIO_AD_05) + D8: Pin ## = Pin(GPIO_SD_02) + D9: Pin ## = Pin(GPIO_03) + D5: Pin ## = Pin(GPIO_01) + SD_TX: Pin ## = Pin(GPIO_04) + SD_RX: Pin ## = Pin(GPIO_03) + PWM_BB: Pin ## = Pin(GPIO_03) + VOLT_DCB: Pin ## = Pin(GPIO_AD_09) + WS_RX: Pin ## = Pin(GPIO_02) + PWM_CB: Pin ## = Pin(GPIO_05) + PWM_BT: Pin ## = Pin(GPIO_04) + SCK_TX: Pin ## = Pin(GPIO_06) + PWM_CT: Pin ## = Pin(GPIO_06) + SCK_RX: Pin ## = Pin(GPIO_01) + WS_TX: Pin ## = Pin(GPIO_07) + CUR_A: Pin ## = Pin(GPIO_AD_01) + A5: Pin ## = Pin(GPIO_AD_02) + CUR_DCB: Pin ## = Pin(GPIO_AD_10) + CUR_B: Pin ## = Pin(GPIO_AD_02) + CUR_C: Pin ## = Pin(GPIO_AD_07) + A1: Pin ## = Pin(GPIO_AD_09) + A0: Pin ## = Pin(GPIO_AD_07) + A4: Pin ## = Pin(GPIO_AD_01) + A2: Pin ## = Pin(GPIO_AD_10) + A3: Pin ## = Pin(GPIO_AD_14) + D4: Pin ## = Pin(GPIO_08) + D15: Pin ## = Pin(GPIO_02) + D14: Pin ## = Pin(GPIO_01) + D0: Pin ## = Pin(GPIO_09) + D2: Pin ## = Pin(GPIO_AD_05) + D3: Pin ## = Pin(GPIO_AD_06) + D10: Pin ## = Pin(GPIO_AD_05) + D1: Pin ## = Pin(GPIO_10) + D13: Pin ## = Pin(GPIO_AD_06) + D11: Pin ## = Pin(GPIO_AD_04) + D12: Pin ## = Pin(GPIO_AD_03) + def __init__(self, *argv, **kwargs) -> None: ... + + def __init__(self, *argv, **kwargs) -> None: ... + +class RTC: + ALARM0: Final[int] = 0 + def irq(self, *args, **kwargs) -> Incomplete: ... + def cancel(self, *args, **kwargs) -> Incomplete: ... + def datetime(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def calibration(self, *args, **kwargs) -> Incomplete: ... + def alarm(self, *args, **kwargs) -> Incomplete: ... + def alarm_cancel(self, *args, **kwargs) -> Incomplete: ... + def alarm_left(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SPI: + LSB: Final[int] = 1 + MSB: Final[int] = 0 + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uos.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uos.pyi new file mode 100644 index 000000000..e6c8d25b6 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uos.pyi @@ -0,0 +1,62 @@ +""" +Module: 'uos' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +sep: str = "/" + +def rmdir(*args, **kwargs) -> Incomplete: ... +def stat(*args, **kwargs) -> Incomplete: ... +def urandom(*args, **kwargs) -> Incomplete: ... +def rename(*args, **kwargs) -> Incomplete: ... +def mount(*args, **kwargs) -> Incomplete: ... +def uname(*args, **kwargs) -> Incomplete: ... +def unlink(*args, **kwargs) -> Incomplete: ... +def statvfs(*args, **kwargs) -> Incomplete: ... +def umount(*args, **kwargs) -> Incomplete: ... +def sync(*args, **kwargs) -> Incomplete: ... +def mkdir(*args, **kwargs) -> Incomplete: ... +def dupterm(*args, **kwargs) -> Incomplete: ... +def chdir(*args, **kwargs) -> Incomplete: ... +def remove(*args, **kwargs) -> Incomplete: ... +def dupterm_notify(*args, **kwargs) -> Incomplete: ... +def listdir(*args, **kwargs) -> Incomplete: ... +def ilistdir(*args, **kwargs) -> Incomplete: ... +def getcwd(*args, **kwargs) -> Incomplete: ... + +class VfsFat: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class VfsLfs2: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uplatform.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uplatform.pyi new file mode 100644 index 000000000..aaa9b944e --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uplatform.pyi @@ -0,0 +1,13 @@ +""" +Module: 'uplatform' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def platform(*args, **kwargs) -> Incomplete: ... +def python_compiler(*args, **kwargs) -> Incomplete: ... +def libc_ver(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/urandom.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/urandom.pyi new file mode 100644 index 000000000..1d73c29f6 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/urandom.pyi @@ -0,0 +1,17 @@ +""" +Module: 'urandom' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def randrange(*args, **kwargs) -> Incomplete: ... +def random(*args, **kwargs) -> Incomplete: ... +def seed(*args, **kwargs) -> Incomplete: ... +def uniform(*args, **kwargs) -> Incomplete: ... +def choice(*args, **kwargs) -> Incomplete: ... +def randint(*args, **kwargs) -> Incomplete: ... +def getrandbits(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ure.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ure.pyi new file mode 100644 index 000000000..461ae6806 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ure.pyi @@ -0,0 +1,14 @@ +""" +Module: 'ure' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def sub(*args, **kwargs) -> Incomplete: ... +def search(*args, **kwargs) -> Incomplete: ... +def match(*args, **kwargs) -> Incomplete: ... +def compile(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device.pyi new file mode 100644 index 000000000..467e898ef --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device.pyi @@ -0,0 +1,10 @@ +""" +Module: 'usb.device' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def get(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device/cdc.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device/cdc.pyi new file mode 100644 index 000000000..a95da0691 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usb/device/cdc.pyi @@ -0,0 +1,77 @@ +""" +Module: 'usb.device.cdc' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +_STOP_BITS_REPR: tuple = () +_PARITY_BITS_REPR: Final[str] = "NOEMS" + +def split_bmRequestType(*args, **kwargs) -> Incomplete: ... +def const(*args, **kwargs) -> Incomplete: ... + +class Buffer: + def finish_read(self, *args, **kwargs) -> Incomplete: ... + def pend_write(self, *args, **kwargs) -> Incomplete: ... + def finish_write(self, *args, **kwargs) -> Incomplete: ... + def pend_read(self, *args, **kwargs) -> Incomplete: ... + def readable(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def writable(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class Interface: + def on_interface_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def stall(self, *args, **kwargs) -> Incomplete: ... + def on_device_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def xfer_pending(self, *args, **kwargs) -> Incomplete: ... + def on_endpoint_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def is_open(self, *args, **kwargs) -> Incomplete: ... + def num_itfs(self, *args, **kwargs) -> Incomplete: ... + def submit_xfer(self, *args, **kwargs) -> Incomplete: ... + def desc_cfg(self, *args, **kwargs) -> Incomplete: ... + def on_reset(self, *args, **kwargs) -> Incomplete: ... + def num_eps(self, *args, **kwargs) -> Incomplete: ... + def on_open(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class CDCInterface: + def xfer_pending(self, *args, **kwargs) -> Incomplete: ... + def is_open(self, *args, **kwargs) -> Incomplete: ... + def stall(self, *args, **kwargs) -> Incomplete: ... + def _readinto(self, *args, **kwargs) -> Incomplete: ... + def on_device_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def on_endpoint_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def on_interface_control_xfer(self, *args, **kwargs) -> Incomplete: ... + def _wr_cb(self, *args, **kwargs) -> Incomplete: ... + def _wr_xfer(self, *args, **kwargs) -> Incomplete: ... + def _rd_cb(self, *args, **kwargs) -> Incomplete: ... + def set_break_cb(self, *args, **kwargs) -> Incomplete: ... + def set_line_state_cb(self, *args, **kwargs) -> Incomplete: ... + def _rd_xfer(self, *args, **kwargs) -> Incomplete: ... + def set_line_coding_cb(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def flush(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def submit_xfer(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def num_eps(self, *args, **kwargs) -> Incomplete: ... + def desc_cfg(self, *args, **kwargs) -> Incomplete: ... + def num_itfs(self, *args, **kwargs) -> Incomplete: ... + def on_reset(self, *args, **kwargs) -> Incomplete: ... + def on_open(self, *args, **kwargs) -> Incomplete: ... + + baudrate: Incomplete ## = + rts: Incomplete ## = + parity: Incomplete ## = + dtr: Incomplete ## = + stop_bits: Incomplete ## = + data_bits: Incomplete ## = + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uselect.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uselect.pyi new file mode 100644 index 000000000..cf07d2909 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/uselect.pyi @@ -0,0 +1,17 @@ +""" +Module: 'uselect' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +POLLOUT: Final[int] = 4 +POLLIN: Final[int] = 1 +POLLHUP: Final[int] = 16 +POLLERR: Final[int] = 8 + +def select(*args, **kwargs) -> Incomplete: ... +def poll(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usocket.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usocket.pyi new file mode 100644 index 000000000..4f6290f03 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usocket.pyi @@ -0,0 +1,44 @@ +""" +Module: 'usocket' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +SO_KEEPALIVE: Final[int] = 8 +SO_BROADCAST: Final[int] = 32 +SOL_SOCKET: Final[int] = 4095 +SO_RCVTIMEO: Final[int] = 4102 +SO_REUSEADDR: Final[int] = 4 +SO_SNDTIMEO: Final[int] = 4101 +AF_INET6: Final[int] = 10 +AF_INET: Final[int] = 2 +SOCK_STREAM: Final[int] = 1 +SOCK_DGRAM: Final[int] = 2 +SOCK_RAW: Final[int] = 3 + +def getaddrinfo(*args, **kwargs) -> Incomplete: ... + +class socket: + def recvfrom(self, *args, **kwargs) -> Incomplete: ... + def recv(self, *args, **kwargs) -> Incomplete: ... + def makefile(self, *args, **kwargs) -> Incomplete: ... + def listen(self, *args, **kwargs) -> Incomplete: ... + def settimeout(self, *args, **kwargs) -> Incomplete: ... + def sendall(self, *args, **kwargs) -> Incomplete: ... + def setsockopt(self, *args, **kwargs) -> Incomplete: ... + def setblocking(self, *args, **kwargs) -> Incomplete: ... + def sendto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def connect(self, *args, **kwargs) -> Incomplete: ... + def send(self, *args, **kwargs) -> Incomplete: ... + def bind(self, *args, **kwargs) -> Incomplete: ... + def accept(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ustruct.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ustruct.pyi new file mode 100644 index 000000000..24711d7a6 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/ustruct.pyi @@ -0,0 +1,15 @@ +""" +Module: 'ustruct' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def pack_into(*args, **kwargs) -> Incomplete: ... +def unpack(*args, **kwargs) -> Incomplete: ... +def unpack_from(*args, **kwargs) -> Incomplete: ... +def pack(*args, **kwargs) -> Incomplete: ... +def calcsize(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usys.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usys.pyi new file mode 100644 index 000000000..e72fc52f8 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/usys.pyi @@ -0,0 +1,28 @@ +""" +Module: 'usys' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +platform: str = "mimxrt" +version_info: tuple = () +path: list = [] +version: str = "3.4.0; MicroPython v1.26.1 on 2025-09-11" +ps1: str = ">>> " +ps2: str = "... " +byteorder: str = "little" +modules: dict = {} +argv: list = [] +implementation: tuple = () +maxsize: int = 2147483647 + +def print_exception(*args, **kwargs) -> Incomplete: ... +def exit(*args, **kwargs) -> Incomplete: ... + +stderr: Incomplete ## = +stdout: Incomplete ## = +stdin: Incomplete ## = diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/utime.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/utime.pyi new file mode 100644 index 000000000..da75ebff0 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/utime.pyi @@ -0,0 +1,23 @@ +""" +Module: 'utime' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Final, Generator +from _typeshed import Incomplete + +def ticks_diff(*args, **kwargs) -> Incomplete: ... +def ticks_add(*args, **kwargs) -> Incomplete: ... +def ticks_cpu(*args, **kwargs) -> Incomplete: ... +def time(*args, **kwargs) -> Incomplete: ... +def ticks_ms(*args, **kwargs) -> Incomplete: ... +def ticks_us(*args, **kwargs) -> Incomplete: ... +def time_ns(*args, **kwargs) -> Incomplete: ... +def localtime(*args, **kwargs) -> Incomplete: ... +def sleep_us(*args, **kwargs) -> Incomplete: ... +def gmtime(*args, **kwargs) -> Incomplete: ... +def sleep_ms(*args, **kwargs) -> Incomplete: ... +def mktime(*args, **kwargs) -> Incomplete: ... +def sleep(*args, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/vfs.pyi b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/vfs.pyi new file mode 100644 index 000000000..f060e52b4 --- /dev/null +++ b/stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK/vfs.pyi @@ -0,0 +1,43 @@ +""" +Module: 'vfs' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def umount(*args, **kwargs) -> Incomplete: ... +def mount(*args, **kwargs) -> Incomplete: ... + +class VfsLfs2: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class VfsFat: + def rename(self, *args, **kwargs) -> Incomplete: ... + def mkfs(self, *args, **kwargs) -> Incomplete: ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... From 116402ac4c8b36f332347a179b25bbccf3968cb4 Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Wed, 26 Nov 2025 10:04:55 +0100 Subject: [PATCH 3/5] Add frozen stubs for v1.26.1 Signed-off-by: Jos Verlinde --- .../alif/GENERIC/_boot.py | 23 + .../alif/GENERIC/_boot.pyi | 3 + .../alif/GENERIC/dht.py | 47 + .../alif/GENERIC/dht.pyi | 15 + .../alif/GENERIC/mip/__init__.py | 187 ++ .../alif/GENERIC/mip/__init__.pyi | 15 + .../alif/GENERIC/modules.json | 64 + .../alif/GENERIC/neopixel.py | 46 + .../alif/GENERIC/neopixel.pyi | 86 + .../alif/GENERIC/ntptime.py | 68 + .../alif/GENERIC/ntptime.pyi | 5 + .../alif/GENERIC/onewire.py | 92 + .../alif/GENERIC/onewire.pyi | 21 + .../alif/GENERIC/removed.txt | 2 + .../alif/GENERIC/requests/__init__.py | 221 +++ .../alif/GENERIC/requests/__init__.pyi | 21 + .../alif/GENERIC/ssl.py | 63 + .../alif/GENERIC/ssl.pyi | 180 ++ .../alif/GENERIC/urequests.py | 8 + .../alif/GENERIC/urequests.pyi | 1 + .../alif/GENERIC/webrepl.py | 178 ++ .../alif/GENERIC/webrepl.pyi | 16 + .../alif/GENERIC/webrepl_setup.py | 105 ++ .../alif/GENERIC/webrepl_setup.pyi | 10 + .../esp32/ARDUINO_NANO_ESP32/_boot.py | 13 + .../esp32/ARDUINO_NANO_ESP32/_boot.pyi | 0 .../ARDUINO_NANO_ESP32/aioble/__init__.py | 32 + .../ARDUINO_NANO_ESP32/aioble/__init__.pyi | 9 + .../ARDUINO_NANO_ESP32/aioble/central.py | 305 ++++ .../ARDUINO_NANO_ESP32/aioble/central.pyi | 70 + .../esp32/ARDUINO_NANO_ESP32/aioble/client.py | 444 +++++ .../ARDUINO_NANO_ESP32/aioble/client.pyi | 101 ++ .../esp32/ARDUINO_NANO_ESP32/aioble/core.py | 78 + .../esp32/ARDUINO_NANO_ESP32/aioble/core.pyi | 23 + .../esp32/ARDUINO_NANO_ESP32/aioble/device.py | 304 ++++ .../ARDUINO_NANO_ESP32/aioble/device.pyi | 66 + .../esp32/ARDUINO_NANO_ESP32/aioble/l2cap.py | 214 +++ .../esp32/ARDUINO_NANO_ESP32/aioble/l2cap.pyi | 40 + .../ARDUINO_NANO_ESP32/aioble/peripheral.py | 176 ++ .../ARDUINO_NANO_ESP32/aioble/peripheral.pyi | 44 + .../ARDUINO_NANO_ESP32/aioble/security.py | 175 ++ .../ARDUINO_NANO_ESP32/aioble/security.pyi | 27 + .../esp32/ARDUINO_NANO_ESP32/aioble/server.py | 336 ++++ .../ARDUINO_NANO_ESP32/aioble/server.pyi | 101 ++ .../esp32/ARDUINO_NANO_ESP32/aioespnow.py | 31 + .../esp32/ARDUINO_NANO_ESP32/aioespnow.pyi | 10 + .../esp32/ARDUINO_NANO_ESP32/apa106.py | 8 + .../esp32/ARDUINO_NANO_ESP32/apa106.pyi | 5 + .../ARDUINO_NANO_ESP32/cbor2/__init__.py | 32 + .../ARDUINO_NANO_ESP32/cbor2/__init__.pyi | 2 + .../ARDUINO_NANO_ESP32/cbor2/_decoder.py | 254 +++ .../ARDUINO_NANO_ESP32/cbor2/_decoder.pyi | 66 + .../ARDUINO_NANO_ESP32/cbor2/_encoder.py | 182 ++ .../ARDUINO_NANO_ESP32/cbor2/_encoder.pyi | 54 + .../esp32/ARDUINO_NANO_ESP32/dht.py | 47 + .../esp32/ARDUINO_NANO_ESP32/dht.pyi | 15 + .../esp32/ARDUINO_NANO_ESP32/ds18x20.py | 52 + .../esp32/ARDUINO_NANO_ESP32/ds18x20.pyi | 16 + .../esp32/ARDUINO_NANO_ESP32/espnow.py | 30 + .../esp32/ARDUINO_NANO_ESP32/espnow.pyi | 294 ++++ .../esp32/ARDUINO_NANO_ESP32/flashbdev.py | 7 + .../esp32/ARDUINO_NANO_ESP32/flashbdev.pyi | 3 + .../esp32/ARDUINO_NANO_ESP32/inisetup.py | 57 + .../esp32/ARDUINO_NANO_ESP32/inisetup.pyi | 3 + .../esp32/ARDUINO_NANO_ESP32/logging.py | 253 +++ .../esp32/ARDUINO_NANO_ESP32/logging.pyi | 86 + .../esp32/ARDUINO_NANO_ESP32/machine.py | 192 +++ .../esp32/ARDUINO_NANO_ESP32/machine.pyi | 1522 +++++++++++++++++ .../esp32/ARDUINO_NANO_ESP32/mip/__init__.py | 187 ++ .../esp32/ARDUINO_NANO_ESP32/mip/__init__.pyi | 15 + .../esp32/ARDUINO_NANO_ESP32/modules.json | 184 ++ .../esp32/ARDUINO_NANO_ESP32/neopixel.py | 46 + .../esp32/ARDUINO_NANO_ESP32/neopixel.pyi | 86 + .../esp32/ARDUINO_NANO_ESP32/ntptime.py | 68 + .../esp32/ARDUINO_NANO_ESP32/ntptime.pyi | 5 + .../esp32/ARDUINO_NANO_ESP32/onewire.py | 92 + .../esp32/ARDUINO_NANO_ESP32/onewire.pyi | 21 + .../esp32/ARDUINO_NANO_ESP32/removed.txt | 2 + .../ARDUINO_NANO_ESP32/requests/__init__.py | 221 +++ .../ARDUINO_NANO_ESP32/requests/__init__.pyi | 21 + .../ARDUINO_NANO_ESP32/senml/__init__.py | 29 + .../ARDUINO_NANO_ESP32/senml/__init__.pyi | 4 + .../ARDUINO_NANO_ESP32/senml/senml_base.py | 30 + .../ARDUINO_NANO_ESP32/senml/senml_base.pyi | 4 + .../ARDUINO_NANO_ESP32/senml/senml_pack.py | 358 ++++ .../ARDUINO_NANO_ESP32/senml/senml_pack.pyi | 143 ++ .../ARDUINO_NANO_ESP32/senml/senml_record.py | 240 +++ .../ARDUINO_NANO_ESP32/senml/senml_record.pyi | 104 ++ .../ARDUINO_NANO_ESP32/senml/senml_unit.py | 89 + .../ARDUINO_NANO_ESP32/senml/senml_unit.pyi | 5 + .../esp32/ARDUINO_NANO_ESP32/ssl.py | 63 + .../esp32/ARDUINO_NANO_ESP32/ssl.pyi | 180 ++ .../esp32/ARDUINO_NANO_ESP32/time.py | 79 + .../esp32/ARDUINO_NANO_ESP32/time.pyi | 59 + .../ARDUINO_NANO_ESP32/umqtt/__init__.py | 0 .../ARDUINO_NANO_ESP32/umqtt/__init__.pyi | 0 .../esp32/ARDUINO_NANO_ESP32/umqtt/robust.py | 53 + .../esp32/ARDUINO_NANO_ESP32/umqtt/robust.pyi | 11 + .../esp32/ARDUINO_NANO_ESP32/umqtt/simple.py | 220 +++ .../esp32/ARDUINO_NANO_ESP32/umqtt/simple.pyi | 33 + .../esp32/ARDUINO_NANO_ESP32/upysh.py | 124 ++ .../esp32/ARDUINO_NANO_ESP32/upysh.pyi | 32 + .../esp32/ARDUINO_NANO_ESP32/urequests.py | 8 + .../esp32/ARDUINO_NANO_ESP32/urequests.pyi | 1 + .../esp32/ARDUINO_NANO_ESP32/webrepl.py | 178 ++ .../esp32/ARDUINO_NANO_ESP32/webrepl.pyi | 16 + .../esp32/ARDUINO_NANO_ESP32/webrepl_setup.py | 105 ++ .../ARDUINO_NANO_ESP32/webrepl_setup.pyi | 10 + .../esp32/GENERIC/_boot.py | 13 + .../esp32/GENERIC/_boot.pyi | 0 .../esp32/GENERIC/aioespnow.py | 31 + .../esp32/GENERIC/aioespnow.pyi | 10 + .../esp32/GENERIC/apa106.py | 8 + .../esp32/GENERIC/apa106.pyi | 5 + .../esp32/GENERIC/dht.py | 47 + .../esp32/GENERIC/dht.pyi | 15 + .../esp32/GENERIC/ds18x20.py | 52 + .../esp32/GENERIC/ds18x20.pyi | 16 + .../esp32/GENERIC/espnow.py | 30 + .../esp32/GENERIC/espnow.pyi | 294 ++++ .../esp32/GENERIC/flashbdev.py | 7 + .../esp32/GENERIC/flashbdev.pyi | 3 + .../esp32/GENERIC/inisetup.py | 57 + .../esp32/GENERIC/inisetup.pyi | 3 + .../esp32/GENERIC/machine.py | 192 +++ .../esp32/GENERIC/machine.pyi | 1522 +++++++++++++++++ .../esp32/GENERIC/mip/__init__.py | 187 ++ .../esp32/GENERIC/mip/__init__.pyi | 15 + .../esp32/GENERIC/modules.json | 108 ++ .../esp32/GENERIC/neopixel.py | 46 + .../esp32/GENERIC/neopixel.pyi | 86 + .../esp32/GENERIC/ntptime.py | 68 + .../esp32/GENERIC/ntptime.pyi | 5 + .../esp32/GENERIC/onewire.py | 92 + .../esp32/GENERIC/onewire.pyi | 21 + .../esp32/GENERIC/removed.txt | 2 + .../esp32/GENERIC/requests/__init__.py | 221 +++ .../esp32/GENERIC/requests/__init__.pyi | 21 + .../esp32/GENERIC/ssl.py | 63 + .../esp32/GENERIC/ssl.pyi | 180 ++ .../esp32/GENERIC/umqtt/__init__.py | 0 .../esp32/GENERIC/umqtt/__init__.pyi | 0 .../esp32/GENERIC/umqtt/robust.py | 53 + .../esp32/GENERIC/umqtt/robust.pyi | 11 + .../esp32/GENERIC/umqtt/simple.py | 220 +++ .../esp32/GENERIC/umqtt/simple.pyi | 33 + .../esp32/GENERIC/upysh.py | 124 ++ .../esp32/GENERIC/upysh.pyi | 32 + .../esp32/GENERIC/urequests.py | 8 + .../esp32/GENERIC/urequests.pyi | 1 + .../esp32/GENERIC/webrepl.py | 178 ++ .../esp32/GENERIC/webrepl.pyi | 16 + .../esp32/GENERIC/webrepl_setup.py | 105 ++ .../esp32/GENERIC/webrepl_setup.pyi | 10 + .../esp32/LILYGO_TTGO_LORA32/_boot.py | 13 + .../esp32/LILYGO_TTGO_LORA32/_boot.pyi | 0 .../esp32/LILYGO_TTGO_LORA32/aioespnow.py | 31 + .../esp32/LILYGO_TTGO_LORA32/aioespnow.pyi | 10 + .../esp32/LILYGO_TTGO_LORA32/apa106.py | 8 + .../esp32/LILYGO_TTGO_LORA32/apa106.pyi | 5 + .../esp32/LILYGO_TTGO_LORA32/dht.py | 47 + .../esp32/LILYGO_TTGO_LORA32/dht.pyi | 15 + .../esp32/LILYGO_TTGO_LORA32/ds18x20.py | 52 + .../esp32/LILYGO_TTGO_LORA32/ds18x20.pyi | 16 + .../esp32/LILYGO_TTGO_LORA32/espnow.py | 30 + .../esp32/LILYGO_TTGO_LORA32/espnow.pyi | 294 ++++ .../esp32/LILYGO_TTGO_LORA32/flashbdev.py | 7 + .../esp32/LILYGO_TTGO_LORA32/flashbdev.pyi | 3 + .../esp32/LILYGO_TTGO_LORA32/inisetup.py | 57 + .../esp32/LILYGO_TTGO_LORA32/inisetup.pyi | 3 + .../esp32/LILYGO_TTGO_LORA32/lilygo_oled.py | 41 + .../esp32/LILYGO_TTGO_LORA32/lilygo_oled.pyi | 6 + .../esp32/LILYGO_TTGO_LORA32/lora32.py | 81 + .../esp32/LILYGO_TTGO_LORA32/lora32.pyi | 48 + .../esp32/LILYGO_TTGO_LORA32/machine.py | 192 +++ .../esp32/LILYGO_TTGO_LORA32/machine.pyi | 1522 +++++++++++++++++ .../esp32/LILYGO_TTGO_LORA32/mip/__init__.py | 187 ++ .../esp32/LILYGO_TTGO_LORA32/mip/__init__.pyi | 15 + .../esp32/LILYGO_TTGO_LORA32/modules.json | 120 ++ .../esp32/LILYGO_TTGO_LORA32/neopixel.py | 46 + .../esp32/LILYGO_TTGO_LORA32/neopixel.pyi | 86 + .../esp32/LILYGO_TTGO_LORA32/ntptime.py | 68 + .../esp32/LILYGO_TTGO_LORA32/ntptime.pyi | 5 + .../esp32/LILYGO_TTGO_LORA32/onewire.py | 92 + .../esp32/LILYGO_TTGO_LORA32/onewire.pyi | 21 + .../esp32/LILYGO_TTGO_LORA32/removed.txt | 2 + .../LILYGO_TTGO_LORA32/requests/__init__.py | 221 +++ .../LILYGO_TTGO_LORA32/requests/__init__.pyi | 21 + .../esp32/LILYGO_TTGO_LORA32/ssd1306.py | 164 ++ .../esp32/LILYGO_TTGO_LORA32/ssd1306.pyi | 56 + .../esp32/LILYGO_TTGO_LORA32/ssl.py | 63 + .../esp32/LILYGO_TTGO_LORA32/ssl.pyi | 180 ++ .../LILYGO_TTGO_LORA32/umqtt/__init__.py | 0 .../LILYGO_TTGO_LORA32/umqtt/__init__.pyi | 0 .../esp32/LILYGO_TTGO_LORA32/umqtt/robust.py | 53 + .../esp32/LILYGO_TTGO_LORA32/umqtt/robust.pyi | 11 + .../esp32/LILYGO_TTGO_LORA32/umqtt/simple.py | 220 +++ .../esp32/LILYGO_TTGO_LORA32/umqtt/simple.pyi | 33 + .../esp32/LILYGO_TTGO_LORA32/upysh.py | 124 ++ .../esp32/LILYGO_TTGO_LORA32/upysh.pyi | 32 + .../esp32/LILYGO_TTGO_LORA32/urequests.py | 8 + .../esp32/LILYGO_TTGO_LORA32/urequests.pyi | 1 + .../esp32/LILYGO_TTGO_LORA32/webrepl.py | 178 ++ .../esp32/LILYGO_TTGO_LORA32/webrepl.pyi | 16 + .../esp32/LILYGO_TTGO_LORA32/webrepl_setup.py | 105 ++ .../LILYGO_TTGO_LORA32/webrepl_setup.pyi | 10 + .../esp32/LOLIN_C3_MINI/_boot.py | 13 + .../esp32/LOLIN_C3_MINI/_boot.pyi | 0 .../esp32/LOLIN_C3_MINI/aioespnow.py | 31 + .../esp32/LOLIN_C3_MINI/aioespnow.pyi | 10 + .../esp32/LOLIN_C3_MINI/apa106.py | 8 + .../esp32/LOLIN_C3_MINI/apa106.pyi | 5 + .../esp32/LOLIN_C3_MINI/c3mini.py | 26 + .../esp32/LOLIN_C3_MINI/c3mini.pyi | 12 + .../esp32/LOLIN_C3_MINI/dht.py | 47 + .../esp32/LOLIN_C3_MINI/dht.pyi | 15 + .../esp32/LOLIN_C3_MINI/ds18x20.py | 52 + .../esp32/LOLIN_C3_MINI/ds18x20.pyi | 16 + .../esp32/LOLIN_C3_MINI/espnow.py | 30 + .../esp32/LOLIN_C3_MINI/espnow.pyi | 294 ++++ .../esp32/LOLIN_C3_MINI/flashbdev.py | 7 + .../esp32/LOLIN_C3_MINI/flashbdev.pyi | 3 + .../esp32/LOLIN_C3_MINI/inisetup.py | 57 + .../esp32/LOLIN_C3_MINI/inisetup.pyi | 3 + .../esp32/LOLIN_C3_MINI/machine.py | 192 +++ .../esp32/LOLIN_C3_MINI/machine.pyi | 1522 +++++++++++++++++ .../esp32/LOLIN_C3_MINI/mip/__init__.py | 187 ++ .../esp32/LOLIN_C3_MINI/mip/__init__.pyi | 15 + .../esp32/LOLIN_C3_MINI/modules.json | 112 ++ .../esp32/LOLIN_C3_MINI/neopixel.py | 46 + .../esp32/LOLIN_C3_MINI/neopixel.pyi | 86 + .../esp32/LOLIN_C3_MINI/ntptime.py | 68 + .../esp32/LOLIN_C3_MINI/ntptime.pyi | 5 + .../esp32/LOLIN_C3_MINI/onewire.py | 92 + .../esp32/LOLIN_C3_MINI/onewire.pyi | 21 + .../esp32/LOLIN_C3_MINI/removed.txt | 2 + .../esp32/LOLIN_C3_MINI/requests/__init__.py | 221 +++ .../esp32/LOLIN_C3_MINI/requests/__init__.pyi | 21 + .../esp32/LOLIN_C3_MINI/ssl.py | 63 + .../esp32/LOLIN_C3_MINI/ssl.pyi | 180 ++ .../esp32/LOLIN_C3_MINI/umqtt/__init__.py | 0 .../esp32/LOLIN_C3_MINI/umqtt/__init__.pyi | 0 .../esp32/LOLIN_C3_MINI/umqtt/robust.py | 53 + .../esp32/LOLIN_C3_MINI/umqtt/robust.pyi | 11 + .../esp32/LOLIN_C3_MINI/umqtt/simple.py | 220 +++ .../esp32/LOLIN_C3_MINI/umqtt/simple.pyi | 33 + .../esp32/LOLIN_C3_MINI/upysh.py | 124 ++ .../esp32/LOLIN_C3_MINI/upysh.pyi | 32 + .../esp32/LOLIN_C3_MINI/urequests.py | 8 + .../esp32/LOLIN_C3_MINI/urequests.pyi | 1 + .../esp32/LOLIN_C3_MINI/webrepl.py | 178 ++ .../esp32/LOLIN_C3_MINI/webrepl.pyi | 16 + .../esp32/LOLIN_C3_MINI/webrepl_setup.py | 105 ++ .../esp32/LOLIN_C3_MINI/webrepl_setup.pyi | 10 + .../esp32/LOLIN_S2_MINI/_boot.py | 13 + .../esp32/LOLIN_S2_MINI/_boot.pyi | 0 .../esp32/LOLIN_S2_MINI/aioespnow.py | 31 + .../esp32/LOLIN_S2_MINI/aioespnow.pyi | 10 + .../esp32/LOLIN_S2_MINI/apa106.py | 8 + .../esp32/LOLIN_S2_MINI/apa106.pyi | 5 + .../esp32/LOLIN_S2_MINI/dht.py | 47 + .../esp32/LOLIN_S2_MINI/dht.pyi | 15 + .../esp32/LOLIN_S2_MINI/ds18x20.py | 52 + .../esp32/LOLIN_S2_MINI/ds18x20.pyi | 16 + .../esp32/LOLIN_S2_MINI/espnow.py | 30 + .../esp32/LOLIN_S2_MINI/espnow.pyi | 294 ++++ .../esp32/LOLIN_S2_MINI/flashbdev.py | 7 + .../esp32/LOLIN_S2_MINI/flashbdev.pyi | 3 + .../esp32/LOLIN_S2_MINI/inisetup.py | 57 + .../esp32/LOLIN_S2_MINI/inisetup.pyi | 3 + .../esp32/LOLIN_S2_MINI/machine.py | 192 +++ .../esp32/LOLIN_S2_MINI/machine.pyi | 1522 +++++++++++++++++ .../esp32/LOLIN_S2_MINI/mip/__init__.py | 187 ++ .../esp32/LOLIN_S2_MINI/mip/__init__.pyi | 15 + .../esp32/LOLIN_S2_MINI/modules.json | 112 ++ .../esp32/LOLIN_S2_MINI/neopixel.py | 46 + .../esp32/LOLIN_S2_MINI/neopixel.pyi | 86 + .../esp32/LOLIN_S2_MINI/ntptime.py | 68 + .../esp32/LOLIN_S2_MINI/ntptime.pyi | 5 + .../esp32/LOLIN_S2_MINI/onewire.py | 92 + .../esp32/LOLIN_S2_MINI/onewire.pyi | 21 + .../esp32/LOLIN_S2_MINI/removed.txt | 2 + .../esp32/LOLIN_S2_MINI/requests/__init__.py | 221 +++ .../esp32/LOLIN_S2_MINI/requests/__init__.pyi | 21 + .../esp32/LOLIN_S2_MINI/s2mini.py | 31 + .../esp32/LOLIN_S2_MINI/s2mini.pyi | 14 + .../esp32/LOLIN_S2_MINI/ssl.py | 63 + .../esp32/LOLIN_S2_MINI/ssl.pyi | 180 ++ .../esp32/LOLIN_S2_MINI/umqtt/__init__.py | 0 .../esp32/LOLIN_S2_MINI/umqtt/__init__.pyi | 0 .../esp32/LOLIN_S2_MINI/umqtt/robust.py | 53 + .../esp32/LOLIN_S2_MINI/umqtt/robust.pyi | 11 + .../esp32/LOLIN_S2_MINI/umqtt/simple.py | 220 +++ .../esp32/LOLIN_S2_MINI/umqtt/simple.pyi | 33 + .../esp32/LOLIN_S2_MINI/upysh.py | 124 ++ .../esp32/LOLIN_S2_MINI/upysh.pyi | 32 + .../esp32/LOLIN_S2_MINI/urequests.py | 8 + .../esp32/LOLIN_S2_MINI/urequests.pyi | 1 + .../esp32/LOLIN_S2_MINI/webrepl.py | 178 ++ .../esp32/LOLIN_S2_MINI/webrepl.pyi | 16 + .../esp32/LOLIN_S2_MINI/webrepl_setup.py | 105 ++ .../esp32/LOLIN_S2_MINI/webrepl_setup.pyi | 10 + .../esp32/LOLIN_S2_PICO/_boot.py | 13 + .../esp32/LOLIN_S2_PICO/_boot.pyi | 0 .../esp32/LOLIN_S2_PICO/aioespnow.py | 31 + .../esp32/LOLIN_S2_PICO/aioespnow.pyi | 10 + .../esp32/LOLIN_S2_PICO/apa106.py | 8 + .../esp32/LOLIN_S2_PICO/apa106.pyi | 5 + .../esp32/LOLIN_S2_PICO/dht.py | 47 + .../esp32/LOLIN_S2_PICO/dht.pyi | 15 + .../esp32/LOLIN_S2_PICO/ds18x20.py | 52 + .../esp32/LOLIN_S2_PICO/ds18x20.pyi | 16 + .../esp32/LOLIN_S2_PICO/espnow.py | 30 + .../esp32/LOLIN_S2_PICO/espnow.pyi | 294 ++++ .../esp32/LOLIN_S2_PICO/flashbdev.py | 7 + .../esp32/LOLIN_S2_PICO/flashbdev.pyi | 3 + .../esp32/LOLIN_S2_PICO/inisetup.py | 57 + .../esp32/LOLIN_S2_PICO/inisetup.pyi | 3 + .../esp32/LOLIN_S2_PICO/machine.py | 192 +++ .../esp32/LOLIN_S2_PICO/machine.pyi | 1522 +++++++++++++++++ .../esp32/LOLIN_S2_PICO/mip/__init__.py | 187 ++ .../esp32/LOLIN_S2_PICO/mip/__init__.pyi | 15 + .../esp32/LOLIN_S2_PICO/modules.json | 120 ++ .../esp32/LOLIN_S2_PICO/neopixel.py | 46 + .../esp32/LOLIN_S2_PICO/neopixel.pyi | 86 + .../esp32/LOLIN_S2_PICO/ntptime.py | 68 + .../esp32/LOLIN_S2_PICO/ntptime.pyi | 5 + .../esp32/LOLIN_S2_PICO/onewire.py | 92 + .../esp32/LOLIN_S2_PICO/onewire.pyi | 21 + .../esp32/LOLIN_S2_PICO/removed.txt | 2 + .../esp32/LOLIN_S2_PICO/requests/__init__.py | 221 +++ .../esp32/LOLIN_S2_PICO/requests/__init__.pyi | 21 + .../esp32/LOLIN_S2_PICO/s2pico.py | 38 + .../esp32/LOLIN_S2_PICO/s2pico.pyi | 17 + .../esp32/LOLIN_S2_PICO/s2pico_oled.py | 48 + .../esp32/LOLIN_S2_PICO/s2pico_oled.pyi | 9 + .../esp32/LOLIN_S2_PICO/ssd1306.py | 164 ++ .../esp32/LOLIN_S2_PICO/ssd1306.pyi | 56 + .../esp32/LOLIN_S2_PICO/ssl.py | 63 + .../esp32/LOLIN_S2_PICO/ssl.pyi | 180 ++ .../esp32/LOLIN_S2_PICO/umqtt/__init__.py | 0 .../esp32/LOLIN_S2_PICO/umqtt/__init__.pyi | 0 .../esp32/LOLIN_S2_PICO/umqtt/robust.py | 53 + .../esp32/LOLIN_S2_PICO/umqtt/robust.pyi | 11 + .../esp32/LOLIN_S2_PICO/umqtt/simple.py | 220 +++ .../esp32/LOLIN_S2_PICO/umqtt/simple.pyi | 33 + .../esp32/LOLIN_S2_PICO/upysh.py | 124 ++ .../esp32/LOLIN_S2_PICO/upysh.pyi | 32 + .../esp32/LOLIN_S2_PICO/urequests.py | 8 + .../esp32/LOLIN_S2_PICO/urequests.pyi | 1 + .../esp32/LOLIN_S2_PICO/webrepl.py | 178 ++ .../esp32/LOLIN_S2_PICO/webrepl.pyi | 16 + .../esp32/LOLIN_S2_PICO/webrepl_setup.py | 105 ++ .../esp32/LOLIN_S2_PICO/webrepl_setup.pyi | 10 + .../esp32/M5STACK_ATOM/_boot.py | 13 + .../esp32/M5STACK_ATOM/_boot.pyi | 0 .../esp32/M5STACK_ATOM/aioespnow.py | 31 + .../esp32/M5STACK_ATOM/aioespnow.pyi | 10 + .../esp32/M5STACK_ATOM/apa106.py | 8 + .../esp32/M5STACK_ATOM/apa106.pyi | 5 + .../esp32/M5STACK_ATOM/atom.py | 75 + .../esp32/M5STACK_ATOM/atom.pyi | 25 + .../esp32/M5STACK_ATOM/dht.py | 47 + .../esp32/M5STACK_ATOM/dht.pyi | 15 + .../esp32/M5STACK_ATOM/ds18x20.py | 52 + .../esp32/M5STACK_ATOM/ds18x20.pyi | 16 + .../esp32/M5STACK_ATOM/espnow.py | 30 + .../esp32/M5STACK_ATOM/espnow.pyi | 294 ++++ .../esp32/M5STACK_ATOM/flashbdev.py | 7 + .../esp32/M5STACK_ATOM/flashbdev.pyi | 3 + .../esp32/M5STACK_ATOM/inisetup.py | 57 + .../esp32/M5STACK_ATOM/inisetup.pyi | 3 + .../esp32/M5STACK_ATOM/machine.py | 192 +++ .../esp32/M5STACK_ATOM/machine.pyi | 1522 +++++++++++++++++ .../esp32/M5STACK_ATOM/mip/__init__.py | 187 ++ .../esp32/M5STACK_ATOM/mip/__init__.pyi | 15 + .../esp32/M5STACK_ATOM/modules.json | 112 ++ .../esp32/M5STACK_ATOM/neopixel.py | 46 + .../esp32/M5STACK_ATOM/neopixel.pyi | 86 + .../esp32/M5STACK_ATOM/ntptime.py | 68 + .../esp32/M5STACK_ATOM/ntptime.pyi | 5 + .../esp32/M5STACK_ATOM/onewire.py | 92 + .../esp32/M5STACK_ATOM/onewire.pyi | 21 + .../esp32/M5STACK_ATOM/removed.txt | 2 + .../esp32/M5STACK_ATOM/requests/__init__.py | 221 +++ .../esp32/M5STACK_ATOM/requests/__init__.pyi | 21 + .../esp32/M5STACK_ATOM/ssl.py | 63 + .../esp32/M5STACK_ATOM/ssl.pyi | 180 ++ .../esp32/M5STACK_ATOM/umqtt/__init__.py | 0 .../esp32/M5STACK_ATOM/umqtt/__init__.pyi | 0 .../esp32/M5STACK_ATOM/umqtt/robust.py | 53 + .../esp32/M5STACK_ATOM/umqtt/robust.pyi | 11 + .../esp32/M5STACK_ATOM/umqtt/simple.py | 220 +++ .../esp32/M5STACK_ATOM/umqtt/simple.pyi | 33 + .../esp32/M5STACK_ATOM/upysh.py | 124 ++ .../esp32/M5STACK_ATOM/upysh.pyi | 32 + .../esp32/M5STACK_ATOM/urequests.py | 8 + .../esp32/M5STACK_ATOM/urequests.pyi | 1 + .../esp32/M5STACK_ATOM/webrepl.py | 178 ++ .../esp32/M5STACK_ATOM/webrepl.pyi | 16 + .../esp32/M5STACK_ATOM/webrepl_setup.py | 105 ++ .../esp32/M5STACK_ATOM/webrepl_setup.pyi | 10 + .../SPARKFUN_IOT_REDBOARD_ESP32/_boot.py | 13 + .../SPARKFUN_IOT_REDBOARD_ESP32/_boot.pyi | 0 .../SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.py | 31 + .../SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.pyi | 10 + .../SPARKFUN_IOT_REDBOARD_ESP32/apa106.py | 8 + .../SPARKFUN_IOT_REDBOARD_ESP32/apa106.pyi | 5 + .../esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.py | 47 + .../esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.pyi | 15 + .../SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.py | 52 + .../SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.pyi | 16 + .../SPARKFUN_IOT_REDBOARD_ESP32/espnow.py | 30 + .../SPARKFUN_IOT_REDBOARD_ESP32/espnow.pyi | 294 ++++ .../SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.py | 7 + .../SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.pyi | 3 + .../SPARKFUN_IOT_REDBOARD_ESP32/inisetup.py | 57 + .../SPARKFUN_IOT_REDBOARD_ESP32/inisetup.pyi | 3 + .../SPARKFUN_IOT_REDBOARD_ESP32/machine.py | 192 +++ .../SPARKFUN_IOT_REDBOARD_ESP32/machine.pyi | 1522 +++++++++++++++++ .../mip/__init__.py | 187 ++ .../mip/__init__.pyi | 15 + .../SPARKFUN_IOT_REDBOARD_ESP32/modules.json | 112 ++ .../SPARKFUN_IOT_REDBOARD_ESP32/neopixel.py | 46 + .../SPARKFUN_IOT_REDBOARD_ESP32/neopixel.pyi | 86 + .../SPARKFUN_IOT_REDBOARD_ESP32/ntptime.py | 68 + .../SPARKFUN_IOT_REDBOARD_ESP32/ntptime.pyi | 5 + .../SPARKFUN_IOT_REDBOARD_ESP32/onewire.py | 92 + .../SPARKFUN_IOT_REDBOARD_ESP32/onewire.pyi | 21 + .../SPARKFUN_IOT_REDBOARD_ESP32/removed.txt | 2 + .../requests/__init__.py | 221 +++ .../requests/__init__.pyi | 21 + .../SPARKFUN_IOT_REDBOARD_ESP32/sdcard.py | 306 ++++ .../SPARKFUN_IOT_REDBOARD_ESP32/sdcard.pyi | 31 + .../esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.py | 63 + .../esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.pyi | 180 ++ .../umqtt/__init__.py | 0 .../umqtt/__init__.pyi | 0 .../umqtt/robust.py | 53 + .../umqtt/robust.pyi | 11 + .../umqtt/simple.py | 220 +++ .../umqtt/simple.pyi | 33 + .../SPARKFUN_IOT_REDBOARD_ESP32/upysh.py | 124 ++ .../SPARKFUN_IOT_REDBOARD_ESP32/upysh.pyi | 32 + .../SPARKFUN_IOT_REDBOARD_ESP32/urequests.py | 8 + .../SPARKFUN_IOT_REDBOARD_ESP32/urequests.pyi | 1 + .../SPARKFUN_IOT_REDBOARD_ESP32/webrepl.py | 178 ++ .../SPARKFUN_IOT_REDBOARD_ESP32/webrepl.pyi | 16 + .../webrepl_setup.py | 105 ++ .../webrepl_setup.pyi | 10 + .../esp32/UM_FEATHERS2/_boot.py | 13 + .../esp32/UM_FEATHERS2/_boot.pyi | 0 .../esp32/UM_FEATHERS2/aioespnow.py | 31 + .../esp32/UM_FEATHERS2/aioespnow.pyi | 10 + .../esp32/UM_FEATHERS2/apa106.py | 8 + .../esp32/UM_FEATHERS2/apa106.pyi | 5 + .../esp32/UM_FEATHERS2/dht.py | 47 + .../esp32/UM_FEATHERS2/dht.pyi | 15 + .../esp32/UM_FEATHERS2/dotstar.py | 225 +++ .../esp32/UM_FEATHERS2/dotstar.pyi | 86 + .../esp32/UM_FEATHERS2/ds18x20.py | 52 + .../esp32/UM_FEATHERS2/ds18x20.pyi | 16 + .../esp32/UM_FEATHERS2/espnow.py | 30 + .../esp32/UM_FEATHERS2/espnow.pyi | 294 ++++ .../esp32/UM_FEATHERS2/feathers2.py | 102 ++ .../esp32/UM_FEATHERS2/feathers2.pyi | 27 + .../esp32/UM_FEATHERS2/flashbdev.py | 7 + .../esp32/UM_FEATHERS2/flashbdev.pyi | 3 + .../esp32/UM_FEATHERS2/inisetup.py | 57 + .../esp32/UM_FEATHERS2/inisetup.pyi | 3 + .../esp32/UM_FEATHERS2/machine.py | 192 +++ .../esp32/UM_FEATHERS2/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_FEATHERS2/mip/__init__.py | 187 ++ .../esp32/UM_FEATHERS2/mip/__init__.pyi | 15 + .../esp32/UM_FEATHERS2/modules.json | 116 ++ .../esp32/UM_FEATHERS2/neopixel.py | 46 + .../esp32/UM_FEATHERS2/neopixel.pyi | 86 + .../esp32/UM_FEATHERS2/ntptime.py | 68 + .../esp32/UM_FEATHERS2/ntptime.pyi | 5 + .../esp32/UM_FEATHERS2/onewire.py | 92 + .../esp32/UM_FEATHERS2/onewire.pyi | 21 + .../esp32/UM_FEATHERS2/removed.txt | 2 + .../esp32/UM_FEATHERS2/requests/__init__.py | 221 +++ .../esp32/UM_FEATHERS2/requests/__init__.pyi | 21 + .../esp32/UM_FEATHERS2/ssl.py | 63 + .../esp32/UM_FEATHERS2/ssl.pyi | 180 ++ .../esp32/UM_FEATHERS2/umqtt/__init__.py | 0 .../esp32/UM_FEATHERS2/umqtt/__init__.pyi | 0 .../esp32/UM_FEATHERS2/umqtt/robust.py | 53 + .../esp32/UM_FEATHERS2/umqtt/robust.pyi | 11 + .../esp32/UM_FEATHERS2/umqtt/simple.py | 220 +++ .../esp32/UM_FEATHERS2/umqtt/simple.pyi | 33 + .../esp32/UM_FEATHERS2/upysh.py | 124 ++ .../esp32/UM_FEATHERS2/upysh.pyi | 32 + .../esp32/UM_FEATHERS2/urequests.py | 8 + .../esp32/UM_FEATHERS2/urequests.pyi | 1 + .../esp32/UM_FEATHERS2/webrepl.py | 178 ++ .../esp32/UM_FEATHERS2/webrepl.pyi | 16 + .../esp32/UM_FEATHERS2/webrepl_setup.py | 105 ++ .../esp32/UM_FEATHERS2/webrepl_setup.pyi | 10 + .../esp32/UM_FEATHERS2NEO/_boot.py | 13 + .../esp32/UM_FEATHERS2NEO/_boot.pyi | 0 .../esp32/UM_FEATHERS2NEO/aioespnow.py | 31 + .../esp32/UM_FEATHERS2NEO/aioespnow.pyi | 10 + .../esp32/UM_FEATHERS2NEO/apa106.py | 8 + .../esp32/UM_FEATHERS2NEO/apa106.pyi | 5 + .../esp32/UM_FEATHERS2NEO/dht.py | 47 + .../esp32/UM_FEATHERS2NEO/dht.pyi | 15 + .../esp32/UM_FEATHERS2NEO/ds18x20.py | 52 + .../esp32/UM_FEATHERS2NEO/ds18x20.pyi | 16 + .../esp32/UM_FEATHERS2NEO/espnow.py | 30 + .../esp32/UM_FEATHERS2NEO/espnow.pyi | 294 ++++ .../esp32/UM_FEATHERS2NEO/feathers2neo.py | 91 + .../esp32/UM_FEATHERS2NEO/feathers2neo.pyi | 36 + .../esp32/UM_FEATHERS2NEO/flashbdev.py | 7 + .../esp32/UM_FEATHERS2NEO/flashbdev.pyi | 3 + .../esp32/UM_FEATHERS2NEO/inisetup.py | 57 + .../esp32/UM_FEATHERS2NEO/inisetup.pyi | 3 + .../esp32/UM_FEATHERS2NEO/machine.py | 192 +++ .../esp32/UM_FEATHERS2NEO/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_FEATHERS2NEO/mip/__init__.py | 187 ++ .../esp32/UM_FEATHERS2NEO/mip/__init__.pyi | 15 + .../esp32/UM_FEATHERS2NEO/modules.json | 112 ++ .../esp32/UM_FEATHERS2NEO/neopixel.py | 46 + .../esp32/UM_FEATHERS2NEO/neopixel.pyi | 86 + .../esp32/UM_FEATHERS2NEO/ntptime.py | 68 + .../esp32/UM_FEATHERS2NEO/ntptime.pyi | 5 + .../esp32/UM_FEATHERS2NEO/onewire.py | 92 + .../esp32/UM_FEATHERS2NEO/onewire.pyi | 21 + .../esp32/UM_FEATHERS2NEO/removed.txt | 2 + .../UM_FEATHERS2NEO/requests/__init__.py | 221 +++ .../UM_FEATHERS2NEO/requests/__init__.pyi | 21 + .../esp32/UM_FEATHERS2NEO/ssl.py | 63 + .../esp32/UM_FEATHERS2NEO/ssl.pyi | 180 ++ .../esp32/UM_FEATHERS2NEO/umqtt/__init__.py | 0 .../esp32/UM_FEATHERS2NEO/umqtt/__init__.pyi | 0 .../esp32/UM_FEATHERS2NEO/umqtt/robust.py | 53 + .../esp32/UM_FEATHERS2NEO/umqtt/robust.pyi | 11 + .../esp32/UM_FEATHERS2NEO/umqtt/simple.py | 220 +++ .../esp32/UM_FEATHERS2NEO/umqtt/simple.pyi | 33 + .../esp32/UM_FEATHERS2NEO/upysh.py | 124 ++ .../esp32/UM_FEATHERS2NEO/upysh.pyi | 32 + .../esp32/UM_FEATHERS2NEO/urequests.py | 8 + .../esp32/UM_FEATHERS2NEO/urequests.pyi | 1 + .../esp32/UM_FEATHERS2NEO/webrepl.py | 178 ++ .../esp32/UM_FEATHERS2NEO/webrepl.pyi | 16 + .../esp32/UM_FEATHERS2NEO/webrepl_setup.py | 105 ++ .../esp32/UM_FEATHERS2NEO/webrepl_setup.pyi | 10 + .../esp32/UM_FEATHERS3/_boot.py | 13 + .../esp32/UM_FEATHERS3/_boot.pyi | 0 .../esp32/UM_FEATHERS3/aioespnow.py | 31 + .../esp32/UM_FEATHERS3/aioespnow.pyi | 10 + .../esp32/UM_FEATHERS3/apa106.py | 8 + .../esp32/UM_FEATHERS3/apa106.pyi | 5 + .../esp32/UM_FEATHERS3/dht.py | 47 + .../esp32/UM_FEATHERS3/dht.pyi | 15 + .../esp32/UM_FEATHERS3/ds18x20.py | 52 + .../esp32/UM_FEATHERS3/ds18x20.pyi | 16 + .../esp32/UM_FEATHERS3/espnow.py | 30 + .../esp32/UM_FEATHERS3/espnow.pyi | 294 ++++ .../esp32/UM_FEATHERS3/feathers3.py | 92 + .../esp32/UM_FEATHERS3/feathers3.pyi | 37 + .../esp32/UM_FEATHERS3/flashbdev.py | 7 + .../esp32/UM_FEATHERS3/flashbdev.pyi | 3 + .../esp32/UM_FEATHERS3/inisetup.py | 57 + .../esp32/UM_FEATHERS3/inisetup.pyi | 3 + .../esp32/UM_FEATHERS3/machine.py | 192 +++ .../esp32/UM_FEATHERS3/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_FEATHERS3/mip/__init__.py | 187 ++ .../esp32/UM_FEATHERS3/mip/__init__.pyi | 15 + .../esp32/UM_FEATHERS3/modules.json | 112 ++ .../esp32/UM_FEATHERS3/neopixel.py | 46 + .../esp32/UM_FEATHERS3/neopixel.pyi | 86 + .../esp32/UM_FEATHERS3/ntptime.py | 68 + .../esp32/UM_FEATHERS3/ntptime.pyi | 5 + .../esp32/UM_FEATHERS3/onewire.py | 92 + .../esp32/UM_FEATHERS3/onewire.pyi | 21 + .../esp32/UM_FEATHERS3/removed.txt | 2 + .../esp32/UM_FEATHERS3/requests/__init__.py | 221 +++ .../esp32/UM_FEATHERS3/requests/__init__.pyi | 21 + .../esp32/UM_FEATHERS3/ssl.py | 63 + .../esp32/UM_FEATHERS3/ssl.pyi | 180 ++ .../esp32/UM_FEATHERS3/umqtt/__init__.py | 0 .../esp32/UM_FEATHERS3/umqtt/__init__.pyi | 0 .../esp32/UM_FEATHERS3/umqtt/robust.py | 53 + .../esp32/UM_FEATHERS3/umqtt/robust.pyi | 11 + .../esp32/UM_FEATHERS3/umqtt/simple.py | 220 +++ .../esp32/UM_FEATHERS3/umqtt/simple.pyi | 33 + .../esp32/UM_FEATHERS3/upysh.py | 124 ++ .../esp32/UM_FEATHERS3/upysh.pyi | 32 + .../esp32/UM_FEATHERS3/urequests.py | 8 + .../esp32/UM_FEATHERS3/urequests.pyi | 1 + .../esp32/UM_FEATHERS3/webrepl.py | 178 ++ .../esp32/UM_FEATHERS3/webrepl.pyi | 16 + .../esp32/UM_FEATHERS3/webrepl_setup.py | 105 ++ .../esp32/UM_FEATHERS3/webrepl_setup.pyi | 10 + .../esp32/UM_FEATHERS3NEO/_boot.py | 13 + .../esp32/UM_FEATHERS3NEO/_boot.pyi | 0 .../esp32/UM_FEATHERS3NEO/aioespnow.py | 31 + .../esp32/UM_FEATHERS3NEO/aioespnow.pyi | 10 + .../esp32/UM_FEATHERS3NEO/apa106.py | 8 + .../esp32/UM_FEATHERS3NEO/apa106.pyi | 5 + .../esp32/UM_FEATHERS3NEO/dht.py | 47 + .../esp32/UM_FEATHERS3NEO/dht.pyi | 15 + .../esp32/UM_FEATHERS3NEO/ds18x20.py | 52 + .../esp32/UM_FEATHERS3NEO/ds18x20.pyi | 16 + .../esp32/UM_FEATHERS3NEO/espnow.py | 30 + .../esp32/UM_FEATHERS3NEO/espnow.pyi | 294 ++++ .../esp32/UM_FEATHERS3NEO/feathers3neo.py | 103 ++ .../esp32/UM_FEATHERS3NEO/feathers3neo.pyi | 44 + .../esp32/UM_FEATHERS3NEO/flashbdev.py | 7 + .../esp32/UM_FEATHERS3NEO/flashbdev.pyi | 3 + .../esp32/UM_FEATHERS3NEO/inisetup.py | 57 + .../esp32/UM_FEATHERS3NEO/inisetup.pyi | 3 + .../esp32/UM_FEATHERS3NEO/machine.py | 192 +++ .../esp32/UM_FEATHERS3NEO/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_FEATHERS3NEO/mip/__init__.py | 187 ++ .../esp32/UM_FEATHERS3NEO/mip/__init__.pyi | 15 + .../esp32/UM_FEATHERS3NEO/modules.json | 112 ++ .../esp32/UM_FEATHERS3NEO/neopixel.py | 46 + .../esp32/UM_FEATHERS3NEO/neopixel.pyi | 86 + .../esp32/UM_FEATHERS3NEO/ntptime.py | 68 + .../esp32/UM_FEATHERS3NEO/ntptime.pyi | 5 + .../esp32/UM_FEATHERS3NEO/onewire.py | 92 + .../esp32/UM_FEATHERS3NEO/onewire.pyi | 21 + .../esp32/UM_FEATHERS3NEO/removed.txt | 2 + .../UM_FEATHERS3NEO/requests/__init__.py | 221 +++ .../UM_FEATHERS3NEO/requests/__init__.pyi | 21 + .../esp32/UM_FEATHERS3NEO/ssl.py | 63 + .../esp32/UM_FEATHERS3NEO/ssl.pyi | 180 ++ .../esp32/UM_FEATHERS3NEO/umqtt/__init__.py | 0 .../esp32/UM_FEATHERS3NEO/umqtt/__init__.pyi | 0 .../esp32/UM_FEATHERS3NEO/umqtt/robust.py | 53 + .../esp32/UM_FEATHERS3NEO/umqtt/robust.pyi | 11 + .../esp32/UM_FEATHERS3NEO/umqtt/simple.py | 220 +++ .../esp32/UM_FEATHERS3NEO/umqtt/simple.pyi | 33 + .../esp32/UM_FEATHERS3NEO/upysh.py | 124 ++ .../esp32/UM_FEATHERS3NEO/upysh.pyi | 32 + .../esp32/UM_FEATHERS3NEO/urequests.py | 8 + .../esp32/UM_FEATHERS3NEO/urequests.pyi | 1 + .../esp32/UM_FEATHERS3NEO/webrepl.py | 178 ++ .../esp32/UM_FEATHERS3NEO/webrepl.pyi | 16 + .../esp32/UM_FEATHERS3NEO/webrepl_setup.py | 105 ++ .../esp32/UM_FEATHERS3NEO/webrepl_setup.pyi | 10 + .../esp32/UM_NANOS3/_boot.py | 13 + .../esp32/UM_NANOS3/_boot.pyi | 0 .../esp32/UM_NANOS3/aioespnow.py | 31 + .../esp32/UM_NANOS3/aioespnow.pyi | 10 + .../esp32/UM_NANOS3/apa106.py | 8 + .../esp32/UM_NANOS3/apa106.pyi | 5 + .../esp32/UM_NANOS3/dht.py | 47 + .../esp32/UM_NANOS3/dht.pyi | 15 + .../esp32/UM_NANOS3/ds18x20.py | 52 + .../esp32/UM_NANOS3/ds18x20.pyi | 16 + .../esp32/UM_NANOS3/espnow.py | 30 + .../esp32/UM_NANOS3/espnow.pyi | 294 ++++ .../esp32/UM_NANOS3/flashbdev.py | 7 + .../esp32/UM_NANOS3/flashbdev.pyi | 3 + .../esp32/UM_NANOS3/inisetup.py | 57 + .../esp32/UM_NANOS3/inisetup.pyi | 3 + .../esp32/UM_NANOS3/machine.py | 192 +++ .../esp32/UM_NANOS3/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_NANOS3/mip/__init__.py | 187 ++ .../esp32/UM_NANOS3/mip/__init__.pyi | 15 + .../esp32/UM_NANOS3/modules.json | 112 ++ .../esp32/UM_NANOS3/nanos3.py | 45 + .../esp32/UM_NANOS3/nanos3.pyi | 16 + .../esp32/UM_NANOS3/neopixel.py | 46 + .../esp32/UM_NANOS3/neopixel.pyi | 86 + .../esp32/UM_NANOS3/ntptime.py | 68 + .../esp32/UM_NANOS3/ntptime.pyi | 5 + .../esp32/UM_NANOS3/onewire.py | 92 + .../esp32/UM_NANOS3/onewire.pyi | 21 + .../esp32/UM_NANOS3/removed.txt | 2 + .../esp32/UM_NANOS3/requests/__init__.py | 221 +++ .../esp32/UM_NANOS3/requests/__init__.pyi | 21 + .../esp32/UM_NANOS3/ssl.py | 63 + .../esp32/UM_NANOS3/ssl.pyi | 180 ++ .../esp32/UM_NANOS3/umqtt/__init__.py | 0 .../esp32/UM_NANOS3/umqtt/__init__.pyi | 0 .../esp32/UM_NANOS3/umqtt/robust.py | 53 + .../esp32/UM_NANOS3/umqtt/robust.pyi | 11 + .../esp32/UM_NANOS3/umqtt/simple.py | 220 +++ .../esp32/UM_NANOS3/umqtt/simple.pyi | 33 + .../esp32/UM_NANOS3/upysh.py | 124 ++ .../esp32/UM_NANOS3/upysh.pyi | 32 + .../esp32/UM_NANOS3/urequests.py | 8 + .../esp32/UM_NANOS3/urequests.pyi | 1 + .../esp32/UM_NANOS3/webrepl.py | 178 ++ .../esp32/UM_NANOS3/webrepl.pyi | 16 + .../esp32/UM_NANOS3/webrepl_setup.py | 105 ++ .../esp32/UM_NANOS3/webrepl_setup.pyi | 10 + .../esp32/UM_OMGS3/_boot.py | 13 + .../esp32/UM_OMGS3/_boot.pyi | 0 .../esp32/UM_OMGS3/aioespnow.py | 31 + .../esp32/UM_OMGS3/aioespnow.pyi | 10 + .../esp32/UM_OMGS3/apa106.py | 8 + .../esp32/UM_OMGS3/apa106.pyi | 5 + .../esp32/UM_OMGS3/dht.py | 47 + .../esp32/UM_OMGS3/dht.pyi | 15 + .../esp32/UM_OMGS3/ds18x20.py | 52 + .../esp32/UM_OMGS3/ds18x20.pyi | 16 + .../esp32/UM_OMGS3/espnow.py | 30 + .../esp32/UM_OMGS3/espnow.pyi | 294 ++++ .../esp32/UM_OMGS3/flashbdev.py | 7 + .../esp32/UM_OMGS3/flashbdev.pyi | 3 + .../esp32/UM_OMGS3/inisetup.py | 57 + .../esp32/UM_OMGS3/inisetup.pyi | 3 + .../esp32/UM_OMGS3/machine.py | 192 +++ .../esp32/UM_OMGS3/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_OMGS3/max17048.py | 72 + .../esp32/UM_OMGS3/max17048.pyi | 35 + .../esp32/UM_OMGS3/mip/__init__.py | 187 ++ .../esp32/UM_OMGS3/mip/__init__.pyi | 15 + .../esp32/UM_OMGS3/modules.json | 116 ++ .../esp32/UM_OMGS3/neopixel.py | 46 + .../esp32/UM_OMGS3/neopixel.pyi | 86 + .../esp32/UM_OMGS3/ntptime.py | 68 + .../esp32/UM_OMGS3/ntptime.pyi | 5 + .../esp32/UM_OMGS3/omgs3.py | 56 + .../esp32/UM_OMGS3/omgs3.pyi | 20 + .../esp32/UM_OMGS3/onewire.py | 92 + .../esp32/UM_OMGS3/onewire.pyi | 21 + .../esp32/UM_OMGS3/removed.txt | 2 + .../esp32/UM_OMGS3/requests/__init__.py | 221 +++ .../esp32/UM_OMGS3/requests/__init__.pyi | 21 + .../esp32/UM_OMGS3/ssl.py | 63 + .../esp32/UM_OMGS3/ssl.pyi | 180 ++ .../esp32/UM_OMGS3/umqtt/__init__.py | 0 .../esp32/UM_OMGS3/umqtt/__init__.pyi | 0 .../esp32/UM_OMGS3/umqtt/robust.py | 53 + .../esp32/UM_OMGS3/umqtt/robust.pyi | 11 + .../esp32/UM_OMGS3/umqtt/simple.py | 220 +++ .../esp32/UM_OMGS3/umqtt/simple.pyi | 33 + .../esp32/UM_OMGS3/upysh.py | 124 ++ .../esp32/UM_OMGS3/upysh.pyi | 32 + .../esp32/UM_OMGS3/urequests.py | 8 + .../esp32/UM_OMGS3/urequests.pyi | 1 + .../esp32/UM_OMGS3/webrepl.py | 178 ++ .../esp32/UM_OMGS3/webrepl.pyi | 16 + .../esp32/UM_OMGS3/webrepl_setup.py | 105 ++ .../esp32/UM_OMGS3/webrepl_setup.pyi | 10 + .../esp32/UM_PROS3/_boot.py | 13 + .../esp32/UM_PROS3/_boot.pyi | 0 .../esp32/UM_PROS3/aioespnow.py | 31 + .../esp32/UM_PROS3/aioespnow.pyi | 10 + .../esp32/UM_PROS3/apa106.py | 8 + .../esp32/UM_PROS3/apa106.pyi | 5 + .../esp32/UM_PROS3/dht.py | 47 + .../esp32/UM_PROS3/dht.pyi | 15 + .../esp32/UM_PROS3/ds18x20.py | 52 + .../esp32/UM_PROS3/ds18x20.pyi | 16 + .../esp32/UM_PROS3/espnow.py | 30 + .../esp32/UM_PROS3/espnow.pyi | 294 ++++ .../esp32/UM_PROS3/flashbdev.py | 7 + .../esp32/UM_PROS3/flashbdev.pyi | 3 + .../esp32/UM_PROS3/inisetup.py | 57 + .../esp32/UM_PROS3/inisetup.pyi | 3 + .../esp32/UM_PROS3/machine.py | 192 +++ .../esp32/UM_PROS3/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_PROS3/mip/__init__.py | 187 ++ .../esp32/UM_PROS3/mip/__init__.pyi | 15 + .../esp32/UM_PROS3/modules.json | 112 ++ .../esp32/UM_PROS3/neopixel.py | 46 + .../esp32/UM_PROS3/neopixel.pyi | 86 + .../esp32/UM_PROS3/ntptime.py | 68 + .../esp32/UM_PROS3/ntptime.pyi | 5 + .../esp32/UM_PROS3/onewire.py | 92 + .../esp32/UM_PROS3/onewire.pyi | 21 + .../esp32/UM_PROS3/pros3.py | 67 + .../esp32/UM_PROS3/pros3.pyi | 26 + .../esp32/UM_PROS3/removed.txt | 2 + .../esp32/UM_PROS3/requests/__init__.py | 221 +++ .../esp32/UM_PROS3/requests/__init__.pyi | 21 + .../esp32/UM_PROS3/ssl.py | 63 + .../esp32/UM_PROS3/ssl.pyi | 180 ++ .../esp32/UM_PROS3/umqtt/__init__.py | 0 .../esp32/UM_PROS3/umqtt/__init__.pyi | 0 .../esp32/UM_PROS3/umqtt/robust.py | 53 + .../esp32/UM_PROS3/umqtt/robust.pyi | 11 + .../esp32/UM_PROS3/umqtt/simple.py | 220 +++ .../esp32/UM_PROS3/umqtt/simple.pyi | 33 + .../esp32/UM_PROS3/upysh.py | 124 ++ .../esp32/UM_PROS3/upysh.pyi | 32 + .../esp32/UM_PROS3/urequests.py | 8 + .../esp32/UM_PROS3/urequests.pyi | 1 + .../esp32/UM_PROS3/webrepl.py | 178 ++ .../esp32/UM_PROS3/webrepl.pyi | 16 + .../esp32/UM_PROS3/webrepl_setup.py | 105 ++ .../esp32/UM_PROS3/webrepl_setup.pyi | 10 + .../esp32/UM_RGBTOUCH_MINI/_boot.py | 13 + .../esp32/UM_RGBTOUCH_MINI/_boot.pyi | 0 .../esp32/UM_RGBTOUCH_MINI/aioespnow.py | 31 + .../esp32/UM_RGBTOUCH_MINI/aioespnow.pyi | 10 + .../esp32/UM_RGBTOUCH_MINI/apa106.py | 8 + .../esp32/UM_RGBTOUCH_MINI/apa106.pyi | 5 + .../esp32/UM_RGBTOUCH_MINI/dht.py | 47 + .../esp32/UM_RGBTOUCH_MINI/dht.pyi | 15 + .../esp32/UM_RGBTOUCH_MINI/ds18x20.py | 52 + .../esp32/UM_RGBTOUCH_MINI/ds18x20.pyi | 16 + .../esp32/UM_RGBTOUCH_MINI/espnow.py | 30 + .../esp32/UM_RGBTOUCH_MINI/espnow.pyi | 294 ++++ .../esp32/UM_RGBTOUCH_MINI/flashbdev.py | 7 + .../esp32/UM_RGBTOUCH_MINI/flashbdev.pyi | 3 + .../esp32/UM_RGBTOUCH_MINI/inisetup.py | 57 + .../esp32/UM_RGBTOUCH_MINI/inisetup.pyi | 3 + .../esp32/UM_RGBTOUCH_MINI/machine.py | 192 +++ .../esp32/UM_RGBTOUCH_MINI/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_RGBTOUCH_MINI/mip/__init__.py | 187 ++ .../esp32/UM_RGBTOUCH_MINI/mip/__init__.pyi | 15 + .../esp32/UM_RGBTOUCH_MINI/modules.json | 108 ++ .../esp32/UM_RGBTOUCH_MINI/neopixel.py | 46 + .../esp32/UM_RGBTOUCH_MINI/neopixel.pyi | 86 + .../esp32/UM_RGBTOUCH_MINI/ntptime.py | 68 + .../esp32/UM_RGBTOUCH_MINI/ntptime.pyi | 5 + .../esp32/UM_RGBTOUCH_MINI/onewire.py | 92 + .../esp32/UM_RGBTOUCH_MINI/onewire.pyi | 21 + .../esp32/UM_RGBTOUCH_MINI/removed.txt | 2 + .../UM_RGBTOUCH_MINI/requests/__init__.py | 221 +++ .../UM_RGBTOUCH_MINI/requests/__init__.pyi | 21 + .../esp32/UM_RGBTOUCH_MINI/ssl.py | 63 + .../esp32/UM_RGBTOUCH_MINI/ssl.pyi | 180 ++ .../esp32/UM_RGBTOUCH_MINI/umqtt/__init__.py | 0 .../esp32/UM_RGBTOUCH_MINI/umqtt/__init__.pyi | 0 .../esp32/UM_RGBTOUCH_MINI/umqtt/robust.py | 53 + .../esp32/UM_RGBTOUCH_MINI/umqtt/robust.pyi | 11 + .../esp32/UM_RGBTOUCH_MINI/umqtt/simple.py | 220 +++ .../esp32/UM_RGBTOUCH_MINI/umqtt/simple.pyi | 33 + .../esp32/UM_RGBTOUCH_MINI/upysh.py | 124 ++ .../esp32/UM_RGBTOUCH_MINI/upysh.pyi | 32 + .../esp32/UM_RGBTOUCH_MINI/urequests.py | 8 + .../esp32/UM_RGBTOUCH_MINI/urequests.pyi | 1 + .../esp32/UM_RGBTOUCH_MINI/webrepl.py | 178 ++ .../esp32/UM_RGBTOUCH_MINI/webrepl.pyi | 16 + .../esp32/UM_RGBTOUCH_MINI/webrepl_setup.py | 105 ++ .../esp32/UM_RGBTOUCH_MINI/webrepl_setup.pyi | 10 + .../esp32/UM_TINYPICO/_boot.py | 13 + .../esp32/UM_TINYPICO/_boot.pyi | 0 .../esp32/UM_TINYPICO/aioespnow.py | 31 + .../esp32/UM_TINYPICO/aioespnow.pyi | 10 + .../esp32/UM_TINYPICO/apa106.py | 8 + .../esp32/UM_TINYPICO/apa106.pyi | 5 + .../esp32/UM_TINYPICO/dht.py | 47 + .../esp32/UM_TINYPICO/dht.pyi | 15 + .../esp32/UM_TINYPICO/dotstar.py | 225 +++ .../esp32/UM_TINYPICO/dotstar.pyi | 86 + .../esp32/UM_TINYPICO/ds18x20.py | 52 + .../esp32/UM_TINYPICO/ds18x20.pyi | 16 + .../esp32/UM_TINYPICO/espnow.py | 30 + .../esp32/UM_TINYPICO/espnow.pyi | 294 ++++ .../esp32/UM_TINYPICO/flashbdev.py | 7 + .../esp32/UM_TINYPICO/flashbdev.pyi | 3 + .../esp32/UM_TINYPICO/inisetup.py | 57 + .../esp32/UM_TINYPICO/inisetup.pyi | 3 + .../esp32/UM_TINYPICO/machine.py | 192 +++ .../esp32/UM_TINYPICO/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_TINYPICO/mip/__init__.py | 187 ++ .../esp32/UM_TINYPICO/mip/__init__.pyi | 15 + .../esp32/UM_TINYPICO/modules.json | 116 ++ .../esp32/UM_TINYPICO/neopixel.py | 46 + .../esp32/UM_TINYPICO/neopixel.pyi | 86 + .../esp32/UM_TINYPICO/ntptime.py | 68 + .../esp32/UM_TINYPICO/ntptime.pyi | 5 + .../esp32/UM_TINYPICO/onewire.py | 92 + .../esp32/UM_TINYPICO/onewire.pyi | 21 + .../esp32/UM_TINYPICO/removed.txt | 2 + .../esp32/UM_TINYPICO/requests/__init__.py | 221 +++ .../esp32/UM_TINYPICO/requests/__init__.pyi | 21 + .../esp32/UM_TINYPICO/ssl.py | 63 + .../esp32/UM_TINYPICO/ssl.pyi | 180 ++ .../esp32/UM_TINYPICO/tinypico.py | 118 ++ .../esp32/UM_TINYPICO/tinypico.pyi | 36 + .../esp32/UM_TINYPICO/umqtt/__init__.py | 0 .../esp32/UM_TINYPICO/umqtt/__init__.pyi | 0 .../esp32/UM_TINYPICO/umqtt/robust.py | 53 + .../esp32/UM_TINYPICO/umqtt/robust.pyi | 11 + .../esp32/UM_TINYPICO/umqtt/simple.py | 220 +++ .../esp32/UM_TINYPICO/umqtt/simple.pyi | 33 + .../esp32/UM_TINYPICO/upysh.py | 124 ++ .../esp32/UM_TINYPICO/upysh.pyi | 32 + .../esp32/UM_TINYPICO/urequests.py | 8 + .../esp32/UM_TINYPICO/urequests.pyi | 1 + .../esp32/UM_TINYPICO/webrepl.py | 178 ++ .../esp32/UM_TINYPICO/webrepl.pyi | 16 + .../esp32/UM_TINYPICO/webrepl_setup.py | 105 ++ .../esp32/UM_TINYPICO/webrepl_setup.pyi | 10 + .../esp32/UM_TINYS2/_boot.py | 13 + .../esp32/UM_TINYS2/_boot.pyi | 0 .../esp32/UM_TINYS2/aioespnow.py | 31 + .../esp32/UM_TINYS2/aioespnow.pyi | 10 + .../esp32/UM_TINYS2/apa106.py | 8 + .../esp32/UM_TINYS2/apa106.pyi | 5 + .../esp32/UM_TINYS2/dht.py | 47 + .../esp32/UM_TINYS2/dht.pyi | 15 + .../esp32/UM_TINYS2/ds18x20.py | 52 + .../esp32/UM_TINYS2/ds18x20.pyi | 16 + .../esp32/UM_TINYS2/espnow.py | 30 + .../esp32/UM_TINYS2/espnow.pyi | 294 ++++ .../esp32/UM_TINYS2/flashbdev.py | 7 + .../esp32/UM_TINYS2/flashbdev.pyi | 3 + .../esp32/UM_TINYS2/inisetup.py | 57 + .../esp32/UM_TINYS2/inisetup.pyi | 3 + .../esp32/UM_TINYS2/machine.py | 192 +++ .../esp32/UM_TINYS2/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_TINYS2/mip/__init__.py | 187 ++ .../esp32/UM_TINYS2/mip/__init__.pyi | 15 + .../esp32/UM_TINYS2/modules.json | 112 ++ .../esp32/UM_TINYS2/neopixel.py | 46 + .../esp32/UM_TINYS2/neopixel.pyi | 86 + .../esp32/UM_TINYS2/ntptime.py | 68 + .../esp32/UM_TINYS2/ntptime.pyi | 5 + .../esp32/UM_TINYS2/onewire.py | 92 + .../esp32/UM_TINYS2/onewire.pyi | 21 + .../esp32/UM_TINYS2/removed.txt | 2 + .../esp32/UM_TINYS2/requests/__init__.py | 221 +++ .../esp32/UM_TINYS2/requests/__init__.pyi | 21 + .../esp32/UM_TINYS2/ssl.py | 63 + .../esp32/UM_TINYS2/ssl.pyi | 180 ++ .../esp32/UM_TINYS2/tinys2.py | 82 + .../esp32/UM_TINYS2/tinys2.pyi | 32 + .../esp32/UM_TINYS2/umqtt/__init__.py | 0 .../esp32/UM_TINYS2/umqtt/__init__.pyi | 0 .../esp32/UM_TINYS2/umqtt/robust.py | 53 + .../esp32/UM_TINYS2/umqtt/robust.pyi | 11 + .../esp32/UM_TINYS2/umqtt/simple.py | 220 +++ .../esp32/UM_TINYS2/umqtt/simple.pyi | 33 + .../esp32/UM_TINYS2/upysh.py | 124 ++ .../esp32/UM_TINYS2/upysh.pyi | 32 + .../esp32/UM_TINYS2/urequests.py | 8 + .../esp32/UM_TINYS2/urequests.pyi | 1 + .../esp32/UM_TINYS2/webrepl.py | 178 ++ .../esp32/UM_TINYS2/webrepl.pyi | 16 + .../esp32/UM_TINYS2/webrepl_setup.py | 105 ++ .../esp32/UM_TINYS2/webrepl_setup.pyi | 10 + .../esp32/UM_TINYS3/_boot.py | 13 + .../esp32/UM_TINYS3/_boot.pyi | 0 .../esp32/UM_TINYS3/aioespnow.py | 31 + .../esp32/UM_TINYS3/aioespnow.pyi | 10 + .../esp32/UM_TINYS3/apa106.py | 8 + .../esp32/UM_TINYS3/apa106.pyi | 5 + .../esp32/UM_TINYS3/dht.py | 47 + .../esp32/UM_TINYS3/dht.pyi | 15 + .../esp32/UM_TINYS3/ds18x20.py | 52 + .../esp32/UM_TINYS3/ds18x20.pyi | 16 + .../esp32/UM_TINYS3/espnow.py | 30 + .../esp32/UM_TINYS3/espnow.pyi | 294 ++++ .../esp32/UM_TINYS3/flashbdev.py | 7 + .../esp32/UM_TINYS3/flashbdev.pyi | 3 + .../esp32/UM_TINYS3/inisetup.py | 57 + .../esp32/UM_TINYS3/inisetup.pyi | 3 + .../esp32/UM_TINYS3/machine.py | 192 +++ .../esp32/UM_TINYS3/machine.pyi | 1522 +++++++++++++++++ .../esp32/UM_TINYS3/mip/__init__.py | 187 ++ .../esp32/UM_TINYS3/mip/__init__.pyi | 15 + .../esp32/UM_TINYS3/modules.json | 112 ++ .../esp32/UM_TINYS3/neopixel.py | 46 + .../esp32/UM_TINYS3/neopixel.pyi | 86 + .../esp32/UM_TINYS3/ntptime.py | 68 + .../esp32/UM_TINYS3/ntptime.pyi | 5 + .../esp32/UM_TINYS3/onewire.py | 92 + .../esp32/UM_TINYS3/onewire.pyi | 21 + .../esp32/UM_TINYS3/removed.txt | 2 + .../esp32/UM_TINYS3/requests/__init__.py | 221 +++ .../esp32/UM_TINYS3/requests/__init__.pyi | 21 + .../esp32/UM_TINYS3/ssl.py | 63 + .../esp32/UM_TINYS3/ssl.pyi | 180 ++ .../esp32/UM_TINYS3/tinys3.py | 67 + .../esp32/UM_TINYS3/tinys3.pyi | 26 + .../esp32/UM_TINYS3/umqtt/__init__.py | 0 .../esp32/UM_TINYS3/umqtt/__init__.pyi | 0 .../esp32/UM_TINYS3/umqtt/robust.py | 53 + .../esp32/UM_TINYS3/umqtt/robust.pyi | 11 + .../esp32/UM_TINYS3/umqtt/simple.py | 220 +++ .../esp32/UM_TINYS3/umqtt/simple.pyi | 33 + .../esp32/UM_TINYS3/upysh.py | 124 ++ .../esp32/UM_TINYS3/upysh.pyi | 32 + .../esp32/UM_TINYS3/urequests.py | 8 + .../esp32/UM_TINYS3/urequests.pyi | 1 + .../esp32/UM_TINYS3/webrepl.py | 178 ++ .../esp32/UM_TINYS3/webrepl.pyi | 16 + .../esp32/UM_TINYS3/webrepl_setup.py | 105 ++ .../esp32/UM_TINYS3/webrepl_setup.pyi | 10 + .../esp8266/GENERIC/_boot.py | 15 + .../esp8266/GENERIC/_boot.pyi | 0 .../esp8266/GENERIC/apa102.py | 17 + .../esp8266/GENERIC/apa102.pyi | 8 + .../esp8266/GENERIC/dht.py | 47 + .../esp8266/GENERIC/dht.pyi | 15 + .../esp8266/GENERIC/ds18x20.py | 52 + .../esp8266/GENERIC/ds18x20.pyi | 16 + .../esp8266/GENERIC/espnow.py | 37 + .../esp8266/GENERIC/espnow.pyi | 284 +++ .../esp8266/GENERIC/flashbdev.py | 42 + .../esp8266/GENERIC/flashbdev.pyi | 14 + .../esp8266/GENERIC/inisetup.py | 68 + .../esp8266/GENERIC/inisetup.pyi | 4 + .../esp8266/GENERIC/mip/__init__.py | 187 ++ .../esp8266/GENERIC/mip/__init__.pyi | 15 + .../esp8266/GENERIC/modules.json | 88 + .../esp8266/GENERIC/neopixel.py | 46 + .../esp8266/GENERIC/neopixel.pyi | 86 + .../esp8266/GENERIC/ntptime.py | 68 + .../esp8266/GENERIC/ntptime.pyi | 5 + .../esp8266/GENERIC/onewire.py | 92 + .../esp8266/GENERIC/onewire.pyi | 21 + .../esp8266/GENERIC/port_diag.py | 32 + .../esp8266/GENERIC/port_diag.pyi | 1 + .../esp8266/GENERIC/requests/__init__.py | 221 +++ .../esp8266/GENERIC/requests/__init__.pyi | 21 + .../esp8266/GENERIC/ssl.py | 63 + .../esp8266/GENERIC/ssl.pyi | 180 ++ .../esp8266/GENERIC/urequests.py | 8 + .../esp8266/GENERIC/urequests.pyi | 1 + .../esp8266/GENERIC/webrepl.py | 178 ++ .../esp8266/GENERIC/webrepl.pyi | 16 + .../esp8266/GENERIC/webrepl_setup.py | 105 ++ .../esp8266/GENERIC/webrepl_setup.pyi | 10 + .../mimxrt/GENERIC/_boot.py | 36 + .../mimxrt/GENERIC/_boot.pyi | 7 + .../mimxrt/GENERIC/dht.py | 47 + .../mimxrt/GENERIC/dht.pyi | 15 + .../mimxrt/GENERIC/ds18x20.py | 52 + .../mimxrt/GENERIC/ds18x20.pyi | 16 + .../mimxrt/GENERIC/modules.json | 36 + .../mimxrt/GENERIC/onewire.py | 92 + .../mimxrt/GENERIC/onewire.pyi | 21 + .../mimxrt/GENERIC/removed.txt | 2 + .../mimxrt/MIMXRT1020_EVK/_boot.py | 36 + .../mimxrt/MIMXRT1020_EVK/_boot.pyi | 7 + .../mimxrt/MIMXRT1020_EVK/dht.py | 47 + .../mimxrt/MIMXRT1020_EVK/dht.pyi | 15 + .../mimxrt/MIMXRT1020_EVK/ds18x20.py | 52 + .../mimxrt/MIMXRT1020_EVK/ds18x20.pyi | 16 + .../mimxrt/MIMXRT1020_EVK/mip/__init__.py | 187 ++ .../mimxrt/MIMXRT1020_EVK/mip/__init__.pyi | 15 + .../mimxrt/MIMXRT1020_EVK/modules.json | 64 + .../mimxrt/MIMXRT1020_EVK/ntptime.py | 68 + .../mimxrt/MIMXRT1020_EVK/ntptime.pyi | 5 + .../mimxrt/MIMXRT1020_EVK/onewire.py | 92 + .../mimxrt/MIMXRT1020_EVK/onewire.pyi | 21 + .../mimxrt/MIMXRT1020_EVK/removed.txt | 2 + .../MIMXRT1020_EVK/requests/__init__.py | 221 +++ .../MIMXRT1020_EVK/requests/__init__.pyi | 21 + .../mimxrt/MIMXRT1020_EVK/ssl.py | 63 + .../mimxrt/MIMXRT1020_EVK/ssl.pyi | 180 ++ .../mimxrt/MIMXRT1020_EVK/urequests.py | 8 + .../mimxrt/MIMXRT1020_EVK/urequests.pyi | 1 + .../mimxrt/MIMXRT1020_EVK/webrepl.py | 178 ++ .../mimxrt/MIMXRT1020_EVK/webrepl.pyi | 16 + .../mimxrt/MIMXRT1020_EVK/webrepl_setup.py | 105 ++ .../mimxrt/MIMXRT1020_EVK/webrepl_setup.pyi | 10 + .../mimxrt/MIMXRT1050_EVK/_boot.py | 36 + .../mimxrt/MIMXRT1050_EVK/_boot.pyi | 7 + .../mimxrt/MIMXRT1050_EVK/dht.py | 47 + .../mimxrt/MIMXRT1050_EVK/dht.pyi | 15 + .../mimxrt/MIMXRT1050_EVK/ds18x20.py | 52 + .../mimxrt/MIMXRT1050_EVK/ds18x20.pyi | 16 + .../mimxrt/MIMXRT1050_EVK/mip/__init__.py | 187 ++ .../mimxrt/MIMXRT1050_EVK/mip/__init__.pyi | 15 + .../mimxrt/MIMXRT1050_EVK/modules.json | 64 + .../mimxrt/MIMXRT1050_EVK/ntptime.py | 68 + .../mimxrt/MIMXRT1050_EVK/ntptime.pyi | 5 + .../mimxrt/MIMXRT1050_EVK/onewire.py | 92 + .../mimxrt/MIMXRT1050_EVK/onewire.pyi | 21 + .../mimxrt/MIMXRT1050_EVK/removed.txt | 2 + .../MIMXRT1050_EVK/requests/__init__.py | 221 +++ .../MIMXRT1050_EVK/requests/__init__.pyi | 21 + .../mimxrt/MIMXRT1050_EVK/ssl.py | 63 + .../mimxrt/MIMXRT1050_EVK/ssl.pyi | 180 ++ .../mimxrt/MIMXRT1050_EVK/urequests.py | 8 + .../mimxrt/MIMXRT1050_EVK/urequests.pyi | 1 + .../mimxrt/MIMXRT1050_EVK/webrepl.py | 178 ++ .../mimxrt/MIMXRT1050_EVK/webrepl.pyi | 16 + .../mimxrt/MIMXRT1050_EVK/webrepl_setup.py | 105 ++ .../mimxrt/MIMXRT1050_EVK/webrepl_setup.pyi | 10 + .../mimxrt/MIMXRT1060_EVK/_boot.py | 36 + .../mimxrt/MIMXRT1060_EVK/_boot.pyi | 7 + .../mimxrt/MIMXRT1060_EVK/dht.py | 47 + .../mimxrt/MIMXRT1060_EVK/dht.pyi | 15 + .../mimxrt/MIMXRT1060_EVK/ds18x20.py | 52 + .../mimxrt/MIMXRT1060_EVK/ds18x20.pyi | 16 + .../mimxrt/MIMXRT1060_EVK/mip/__init__.py | 187 ++ .../mimxrt/MIMXRT1060_EVK/mip/__init__.pyi | 15 + .../mimxrt/MIMXRT1060_EVK/modules.json | 64 + .../mimxrt/MIMXRT1060_EVK/ntptime.py | 68 + .../mimxrt/MIMXRT1060_EVK/ntptime.pyi | 5 + .../mimxrt/MIMXRT1060_EVK/onewire.py | 92 + .../mimxrt/MIMXRT1060_EVK/onewire.pyi | 21 + .../mimxrt/MIMXRT1060_EVK/removed.txt | 2 + .../MIMXRT1060_EVK/requests/__init__.py | 221 +++ .../MIMXRT1060_EVK/requests/__init__.pyi | 21 + .../mimxrt/MIMXRT1060_EVK/ssl.py | 63 + .../mimxrt/MIMXRT1060_EVK/ssl.pyi | 180 ++ .../mimxrt/MIMXRT1060_EVK/urequests.py | 8 + .../mimxrt/MIMXRT1060_EVK/urequests.pyi | 1 + .../mimxrt/MIMXRT1060_EVK/webrepl.py | 178 ++ .../mimxrt/MIMXRT1060_EVK/webrepl.pyi | 16 + .../mimxrt/MIMXRT1060_EVK/webrepl_setup.py | 105 ++ .../mimxrt/MIMXRT1060_EVK/webrepl_setup.pyi | 10 + .../mimxrt/MIMXRT1064_EVK/_boot.py | 36 + .../mimxrt/MIMXRT1064_EVK/_boot.pyi | 7 + .../mimxrt/MIMXRT1064_EVK/dht.py | 47 + .../mimxrt/MIMXRT1064_EVK/dht.pyi | 15 + .../mimxrt/MIMXRT1064_EVK/ds18x20.py | 52 + .../mimxrt/MIMXRT1064_EVK/ds18x20.pyi | 16 + .../mimxrt/MIMXRT1064_EVK/mip/__init__.py | 187 ++ .../mimxrt/MIMXRT1064_EVK/mip/__init__.pyi | 15 + .../mimxrt/MIMXRT1064_EVK/modules.json | 64 + .../mimxrt/MIMXRT1064_EVK/ntptime.py | 68 + .../mimxrt/MIMXRT1064_EVK/ntptime.pyi | 5 + .../mimxrt/MIMXRT1064_EVK/onewire.py | 92 + .../mimxrt/MIMXRT1064_EVK/onewire.pyi | 21 + .../mimxrt/MIMXRT1064_EVK/removed.txt | 2 + .../MIMXRT1064_EVK/requests/__init__.py | 221 +++ .../MIMXRT1064_EVK/requests/__init__.pyi | 21 + .../mimxrt/MIMXRT1064_EVK/ssl.py | 63 + .../mimxrt/MIMXRT1064_EVK/ssl.pyi | 180 ++ .../mimxrt/MIMXRT1064_EVK/urequests.py | 8 + .../mimxrt/MIMXRT1064_EVK/urequests.pyi | 1 + .../mimxrt/MIMXRT1064_EVK/webrepl.py | 178 ++ .../mimxrt/MIMXRT1064_EVK/webrepl.pyi | 16 + .../mimxrt/MIMXRT1064_EVK/webrepl_setup.py | 105 ++ .../mimxrt/MIMXRT1064_EVK/webrepl_setup.pyi | 10 + .../mimxrt/MIMXRT1170_EVK/_boot.py | 36 + .../mimxrt/MIMXRT1170_EVK/_boot.pyi | 7 + .../mimxrt/MIMXRT1170_EVK/dht.py | 47 + .../mimxrt/MIMXRT1170_EVK/dht.pyi | 15 + .../mimxrt/MIMXRT1170_EVK/ds18x20.py | 52 + .../mimxrt/MIMXRT1170_EVK/ds18x20.pyi | 16 + .../mimxrt/MIMXRT1170_EVK/mip/__init__.py | 187 ++ .../mimxrt/MIMXRT1170_EVK/mip/__init__.pyi | 15 + .../mimxrt/MIMXRT1170_EVK/modules.json | 64 + .../mimxrt/MIMXRT1170_EVK/ntptime.py | 68 + .../mimxrt/MIMXRT1170_EVK/ntptime.pyi | 5 + .../mimxrt/MIMXRT1170_EVK/onewire.py | 92 + .../mimxrt/MIMXRT1170_EVK/onewire.pyi | 21 + .../mimxrt/MIMXRT1170_EVK/removed.txt | 2 + .../MIMXRT1170_EVK/requests/__init__.py | 221 +++ .../MIMXRT1170_EVK/requests/__init__.pyi | 21 + .../mimxrt/MIMXRT1170_EVK/ssl.py | 63 + .../mimxrt/MIMXRT1170_EVK/ssl.pyi | 180 ++ .../mimxrt/MIMXRT1170_EVK/urequests.py | 8 + .../mimxrt/MIMXRT1170_EVK/urequests.pyi | 1 + .../mimxrt/MIMXRT1170_EVK/webrepl.py | 178 ++ .../mimxrt/MIMXRT1170_EVK/webrepl.pyi | 16 + .../mimxrt/MIMXRT1170_EVK/webrepl_setup.py | 105 ++ .../mimxrt/MIMXRT1170_EVK/webrepl_setup.pyi | 10 + .../mimxrt/SEEED_ARCH_MIX/_boot.py | 36 + .../mimxrt/SEEED_ARCH_MIX/_boot.pyi | 7 + .../mimxrt/SEEED_ARCH_MIX/dht.py | 47 + .../mimxrt/SEEED_ARCH_MIX/dht.pyi | 15 + .../mimxrt/SEEED_ARCH_MIX/ds18x20.py | 52 + .../mimxrt/SEEED_ARCH_MIX/ds18x20.pyi | 16 + .../mimxrt/SEEED_ARCH_MIX/mip/__init__.py | 187 ++ .../mimxrt/SEEED_ARCH_MIX/mip/__init__.pyi | 15 + .../mimxrt/SEEED_ARCH_MIX/modules.json | 64 + .../mimxrt/SEEED_ARCH_MIX/ntptime.py | 68 + .../mimxrt/SEEED_ARCH_MIX/ntptime.pyi | 5 + .../mimxrt/SEEED_ARCH_MIX/onewire.py | 92 + .../mimxrt/SEEED_ARCH_MIX/onewire.pyi | 21 + .../mimxrt/SEEED_ARCH_MIX/removed.txt | 2 + .../SEEED_ARCH_MIX/requests/__init__.py | 221 +++ .../SEEED_ARCH_MIX/requests/__init__.pyi | 21 + .../mimxrt/SEEED_ARCH_MIX/ssl.py | 63 + .../mimxrt/SEEED_ARCH_MIX/ssl.pyi | 180 ++ .../mimxrt/SEEED_ARCH_MIX/urequests.py | 8 + .../mimxrt/SEEED_ARCH_MIX/urequests.pyi | 1 + .../mimxrt/SEEED_ARCH_MIX/webrepl.py | 178 ++ .../mimxrt/SEEED_ARCH_MIX/webrepl.pyi | 16 + .../mimxrt/SEEED_ARCH_MIX/webrepl_setup.py | 105 ++ .../mimxrt/SEEED_ARCH_MIX/webrepl_setup.pyi | 10 + .../mimxrt/TEENSY41/_boot.py | 36 + .../mimxrt/TEENSY41/_boot.pyi | 7 + .../mimxrt/TEENSY41/dht.py | 47 + .../mimxrt/TEENSY41/dht.pyi | 15 + .../mimxrt/TEENSY41/ds18x20.py | 52 + .../mimxrt/TEENSY41/ds18x20.pyi | 16 + .../mimxrt/TEENSY41/mip/__init__.py | 187 ++ .../mimxrt/TEENSY41/mip/__init__.pyi | 15 + .../mimxrt/TEENSY41/modules.json | 64 + .../mimxrt/TEENSY41/ntptime.py | 68 + .../mimxrt/TEENSY41/ntptime.pyi | 5 + .../mimxrt/TEENSY41/onewire.py | 92 + .../mimxrt/TEENSY41/onewire.pyi | 21 + .../mimxrt/TEENSY41/removed.txt | 2 + .../mimxrt/TEENSY41/requests/__init__.py | 221 +++ .../mimxrt/TEENSY41/requests/__init__.pyi | 21 + .../mimxrt/TEENSY41/ssl.py | 63 + .../mimxrt/TEENSY41/ssl.pyi | 180 ++ .../mimxrt/TEENSY41/urequests.py | 8 + .../mimxrt/TEENSY41/urequests.pyi | 1 + .../mimxrt/TEENSY41/webrepl.py | 178 ++ .../mimxrt/TEENSY41/webrepl.pyi | 16 + .../mimxrt/TEENSY41/webrepl_setup.py | 105 ++ .../mimxrt/TEENSY41/webrepl_setup.pyi | 10 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.py | 23 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.pyi | 4 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.py | 634 +++++++ .../nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.pyi | 53 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.py | 184 ++ .../nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.pyi | 53 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.py | 64 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.pyi | 11 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.py | 89 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.pyi | 18 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/imu.py | 43 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/imu.pyi | 9 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.py | 105 ++ .../nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.pyi | 24 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/lsm9ds1.py | 201 +++ .../nrf/ARDUINO_NANO_33_BLE_SENSE/lsm9ds1.pyi | 71 + .../ARDUINO_NANO_33_BLE_SENSE/modules.json | 52 + .../nrf/ARDUINO_NANO_33_BLE_SENSE/removed.txt | 2 + .../nrf/GENERIC/_mkfs.py | 23 + .../nrf/GENERIC/_mkfs.pyi | 4 + .../nrf/GENERIC/modules.json | 24 + .../nrf/GENERIC/removed.txt | 2 + .../ARDUINO_PORTENTA_C33/aioble/__init__.py | 32 + .../ARDUINO_PORTENTA_C33/aioble/__init__.pyi | 9 + .../ARDUINO_PORTENTA_C33/aioble/central.py | 305 ++++ .../ARDUINO_PORTENTA_C33/aioble/central.pyi | 70 + .../ARDUINO_PORTENTA_C33/aioble/client.py | 444 +++++ .../ARDUINO_PORTENTA_C33/aioble/client.pyi | 101 ++ .../ARDUINO_PORTENTA_C33/aioble/core.py | 78 + .../ARDUINO_PORTENTA_C33/aioble/core.pyi | 23 + .../ARDUINO_PORTENTA_C33/aioble/device.py | 304 ++++ .../ARDUINO_PORTENTA_C33/aioble/device.pyi | 66 + .../ARDUINO_PORTENTA_C33/aioble/l2cap.py | 214 +++ .../ARDUINO_PORTENTA_C33/aioble/l2cap.pyi | 40 + .../ARDUINO_PORTENTA_C33/aioble/peripheral.py | 176 ++ .../aioble/peripheral.pyi | 44 + .../ARDUINO_PORTENTA_C33/aioble/security.py | 175 ++ .../ARDUINO_PORTENTA_C33/aioble/security.pyi | 27 + .../ARDUINO_PORTENTA_C33/aioble/server.py | 336 ++++ .../ARDUINO_PORTENTA_C33/aioble/server.pyi | 101 ++ .../ARDUINO_PORTENTA_C33/cbor2/__init__.py | 32 + .../ARDUINO_PORTENTA_C33/cbor2/__init__.pyi | 2 + .../ARDUINO_PORTENTA_C33/cbor2/_decoder.py | 254 +++ .../ARDUINO_PORTENTA_C33/cbor2/_decoder.pyi | 66 + .../ARDUINO_PORTENTA_C33/cbor2/_encoder.py | 182 ++ .../ARDUINO_PORTENTA_C33/cbor2/_encoder.pyi | 54 + .../renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.py | 357 ++++ .../renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.pyi | 81 + .../renesas-ra/ARDUINO_PORTENTA_C33/dht.py | 47 + .../renesas-ra/ARDUINO_PORTENTA_C33/dht.pyi | 15 + .../ARDUINO_PORTENTA_C33/logging.py | 253 +++ .../ARDUINO_PORTENTA_C33/logging.pyi | 86 + .../ARDUINO_PORTENTA_C33/mip/__init__.py | 187 ++ .../ARDUINO_PORTENTA_C33/mip/__init__.pyi | 15 + .../ARDUINO_PORTENTA_C33/modules.json | 136 ++ .../ARDUINO_PORTENTA_C33/ntptime.py | 68 + .../ARDUINO_PORTENTA_C33/ntptime.pyi | 5 + .../ARDUINO_PORTENTA_C33/onewire.py | 92 + .../ARDUINO_PORTENTA_C33/onewire.pyi | 21 + .../ARDUINO_PORTENTA_C33/removed.txt | 2 + .../ARDUINO_PORTENTA_C33/requests/__init__.py | 221 +++ .../requests/__init__.pyi | 21 + .../ARDUINO_PORTENTA_C33/senml/__init__.py | 29 + .../ARDUINO_PORTENTA_C33/senml/__init__.pyi | 4 + .../ARDUINO_PORTENTA_C33/senml/senml_base.py | 30 + .../ARDUINO_PORTENTA_C33/senml/senml_base.pyi | 4 + .../ARDUINO_PORTENTA_C33/senml/senml_pack.py | 358 ++++ .../ARDUINO_PORTENTA_C33/senml/senml_pack.pyi | 143 ++ .../senml/senml_record.py | 240 +++ .../senml/senml_record.pyi | 104 ++ .../ARDUINO_PORTENTA_C33/senml/senml_unit.py | 89 + .../ARDUINO_PORTENTA_C33/senml/senml_unit.pyi | 5 + .../renesas-ra/ARDUINO_PORTENTA_C33/ssl.py | 63 + .../renesas-ra/ARDUINO_PORTENTA_C33/ssl.pyi | 180 ++ .../renesas-ra/ARDUINO_PORTENTA_C33/time.py | 79 + .../renesas-ra/ARDUINO_PORTENTA_C33/time.pyi | 59 + .../ARDUINO_PORTENTA_C33/urequests.py | 8 + .../ARDUINO_PORTENTA_C33/urequests.pyi | 1 + .../ARDUINO_PORTENTA_C33/webrepl.py | 178 ++ .../ARDUINO_PORTENTA_C33/webrepl.pyi | 16 + .../ARDUINO_PORTENTA_C33/webrepl_setup.py | 105 ++ .../ARDUINO_PORTENTA_C33/webrepl_setup.pyi | 10 + .../renesas-ra/EK_RA4M1/modules.json | 24 + .../renesas-ra/EK_RA4M1/sdcard.py | 306 ++++ .../renesas-ra/EK_RA4M1/sdcard.pyi | 31 + .../renesas-ra/GENERIC/dht.py | 47 + .../renesas-ra/GENERIC/dht.pyi | 15 + .../renesas-ra/GENERIC/modules.json | 28 + .../renesas-ra/GENERIC/onewire.py | 92 + .../renesas-ra/GENERIC/onewire.pyi | 21 + .../renesas-ra/GENERIC/removed.txt | 2 + .../renesas-ra/RA4M1_CLICKER/modules.json | 24 + .../renesas-ra/RA4M1_CLICKER/sdcard.py | 306 ++++ .../renesas-ra/RA4M1_CLICKER/sdcard.pyi | 31 + .../rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.py | 16 + .../rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.pyi | 4 + .../ARDUINO_NANO_RP2040_CONNECT/_boot_fat.py | 14 + .../ARDUINO_NANO_RP2040_CONNECT/_boot_fat.pyi | 3 + .../aioble/__init__.py | 32 + .../aioble/__init__.pyi | 9 + .../aioble/central.py | 305 ++++ .../aioble/central.pyi | 70 + .../aioble/client.py | 444 +++++ .../aioble/client.pyi | 101 ++ .../aioble/core.py | 78 + .../aioble/core.pyi | 23 + .../aioble/device.py | 304 ++++ .../aioble/device.pyi | 66 + .../aioble/l2cap.py | 214 +++ .../aioble/l2cap.pyi | 40 + .../aioble/peripheral.py | 176 ++ .../aioble/peripheral.pyi | 44 + .../aioble/security.py | 175 ++ .../aioble/security.pyi | 27 + .../aioble/server.py | 336 ++++ .../aioble/server.pyi | 101 ++ .../cbor2/__init__.py | 32 + .../cbor2/__init__.pyi | 2 + .../cbor2/_decoder.py | 254 +++ .../cbor2/_decoder.pyi | 66 + .../cbor2/_encoder.py | 182 ++ .../cbor2/_encoder.pyi | 54 + .../rp2/ARDUINO_NANO_RP2040_CONNECT/dht.py | 47 + .../rp2/ARDUINO_NANO_RP2040_CONNECT/dht.pyi | 15 + .../ARDUINO_NANO_RP2040_CONNECT/ds18x20.py | 52 + .../ARDUINO_NANO_RP2040_CONNECT/ds18x20.pyi | 16 + .../ARDUINO_NANO_RP2040_CONNECT/espflash.py | 303 ++++ .../ARDUINO_NANO_RP2040_CONNECT/espflash.pyi | 46 + .../ARDUINO_NANO_RP2040_CONNECT/logging.py | 253 +++ .../ARDUINO_NANO_RP2040_CONNECT/logging.pyi | 86 + .../ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.py | 272 +++ .../ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.pyi | 54 + .../mip/__init__.py | 187 ++ .../mip/__init__.pyi | 15 + .../ARDUINO_NANO_RP2040_CONNECT/modules.json | 156 ++ .../ARDUINO_NANO_RP2040_CONNECT/neopixel.py | 46 + .../ARDUINO_NANO_RP2040_CONNECT/neopixel.pyi | 86 + .../ARDUINO_NANO_RP2040_CONNECT/ntptime.py | 68 + .../ARDUINO_NANO_RP2040_CONNECT/ntptime.pyi | 5 + .../ARDUINO_NANO_RP2040_CONNECT/onewire.py | 92 + .../ARDUINO_NANO_RP2040_CONNECT/onewire.pyi | 21 + .../ARDUINO_NANO_RP2040_CONNECT/removed.txt | 2 + .../requests/__init__.py | 221 +++ .../requests/__init__.pyi | 21 + .../senml/__init__.py | 29 + .../senml/__init__.pyi | 4 + .../senml/senml_base.py | 30 + .../senml/senml_base.pyi | 4 + .../senml/senml_pack.py | 358 ++++ .../senml/senml_pack.pyi | 143 ++ .../senml/senml_record.py | 240 +++ .../senml/senml_record.pyi | 104 ++ .../senml/senml_unit.py | 89 + .../senml/senml_unit.pyi | 5 + .../rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.py | 63 + .../rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.pyi | 180 ++ .../rp2/ARDUINO_NANO_RP2040_CONNECT/time.py | 79 + .../rp2/ARDUINO_NANO_RP2040_CONNECT/time.pyi | 59 + .../ARDUINO_NANO_RP2040_CONNECT/urequests.py | 8 + .../ARDUINO_NANO_RP2040_CONNECT/urequests.pyi | 1 + .../ARDUINO_NANO_RP2040_CONNECT/webrepl.py | 178 ++ .../ARDUINO_NANO_RP2040_CONNECT/webrepl.pyi | 16 + .../webrepl_setup.py | 105 ++ .../webrepl_setup.pyi | 10 + .../rp2/GENERIC/_boot.py | 16 + .../rp2/GENERIC/_boot.pyi | 4 + .../rp2/GENERIC/_boot_fat.py | 14 + .../rp2/GENERIC/_boot_fat.pyi | 3 + .../rp2/GENERIC/dht.py | 47 + .../rp2/GENERIC/dht.pyi | 15 + .../rp2/GENERIC/ds18x20.py | 52 + .../rp2/GENERIC/ds18x20.pyi | 16 + .../rp2/GENERIC/modules.json | 44 + .../rp2/GENERIC/neopixel.py | 46 + .../rp2/GENERIC/neopixel.pyi | 86 + .../rp2/GENERIC/onewire.py | 92 + .../rp2/GENERIC/onewire.pyi | 21 + .../rp2/GENERIC/removed.txt | 2 + .../rp2/NULLBITS_BIT_C_PRO/_boot.py | 16 + .../rp2/NULLBITS_BIT_C_PRO/_boot.pyi | 4 + .../rp2/NULLBITS_BIT_C_PRO/_boot_fat.py | 14 + .../rp2/NULLBITS_BIT_C_PRO/_boot_fat.pyi | 3 + .../rp2/NULLBITS_BIT_C_PRO/board.py | 7 + .../rp2/NULLBITS_BIT_C_PRO/board.pyi | 5 + .../rp2/NULLBITS_BIT_C_PRO/dht.py | 47 + .../rp2/NULLBITS_BIT_C_PRO/dht.pyi | 15 + .../rp2/NULLBITS_BIT_C_PRO/ds18x20.py | 52 + .../rp2/NULLBITS_BIT_C_PRO/ds18x20.pyi | 16 + .../rp2/NULLBITS_BIT_C_PRO/modules.json | 48 + .../rp2/NULLBITS_BIT_C_PRO/neopixel.py | 46 + .../rp2/NULLBITS_BIT_C_PRO/neopixel.pyi | 86 + .../rp2/NULLBITS_BIT_C_PRO/onewire.py | 92 + .../rp2/NULLBITS_BIT_C_PRO/onewire.pyi | 21 + .../rp2/NULLBITS_BIT_C_PRO/removed.txt | 2 + .../rp2/RPI_PICO2_W/_boot.py | 16 + .../rp2/RPI_PICO2_W/_boot.pyi | 4 + .../rp2/RPI_PICO2_W/_boot_fat.py | 14 + .../rp2/RPI_PICO2_W/_boot_fat.pyi | 3 + .../rp2/RPI_PICO2_W/aioble/__init__.py | 32 + .../rp2/RPI_PICO2_W/aioble/__init__.pyi | 9 + .../rp2/RPI_PICO2_W/aioble/central.py | 305 ++++ .../rp2/RPI_PICO2_W/aioble/central.pyi | 70 + .../rp2/RPI_PICO2_W/aioble/client.py | 444 +++++ .../rp2/RPI_PICO2_W/aioble/client.pyi | 101 ++ .../rp2/RPI_PICO2_W/aioble/core.py | 78 + .../rp2/RPI_PICO2_W/aioble/core.pyi | 23 + .../rp2/RPI_PICO2_W/aioble/device.py | 304 ++++ .../rp2/RPI_PICO2_W/aioble/device.pyi | 66 + .../rp2/RPI_PICO2_W/aioble/l2cap.py | 214 +++ .../rp2/RPI_PICO2_W/aioble/l2cap.pyi | 40 + .../rp2/RPI_PICO2_W/aioble/peripheral.py | 176 ++ .../rp2/RPI_PICO2_W/aioble/peripheral.pyi | 44 + .../rp2/RPI_PICO2_W/aioble/security.py | 175 ++ .../rp2/RPI_PICO2_W/aioble/security.pyi | 27 + .../rp2/RPI_PICO2_W/aioble/server.py | 336 ++++ .../rp2/RPI_PICO2_W/aioble/server.pyi | 101 ++ .../rp2/RPI_PICO2_W/dht.py | 47 + .../rp2/RPI_PICO2_W/dht.pyi | 15 + .../rp2/RPI_PICO2_W/ds18x20.py | 52 + .../rp2/RPI_PICO2_W/ds18x20.pyi | 16 + .../rp2/RPI_PICO2_W/mip/__init__.py | 187 ++ .../rp2/RPI_PICO2_W/mip/__init__.pyi | 15 + .../rp2/RPI_PICO2_W/modules.json | 108 ++ .../rp2/RPI_PICO2_W/neopixel.py | 46 + .../rp2/RPI_PICO2_W/neopixel.pyi | 86 + .../rp2/RPI_PICO2_W/ntptime.py | 68 + .../rp2/RPI_PICO2_W/ntptime.pyi | 5 + .../rp2/RPI_PICO2_W/onewire.py | 92 + .../rp2/RPI_PICO2_W/onewire.pyi | 21 + .../rp2/RPI_PICO2_W/removed.txt | 2 + .../rp2/RPI_PICO2_W/requests/__init__.py | 221 +++ .../rp2/RPI_PICO2_W/requests/__init__.pyi | 21 + .../rp2/RPI_PICO2_W/ssl.py | 63 + .../rp2/RPI_PICO2_W/ssl.pyi | 180 ++ .../rp2/RPI_PICO2_W/urequests.py | 8 + .../rp2/RPI_PICO2_W/urequests.pyi | 1 + .../rp2/RPI_PICO2_W/webrepl.py | 178 ++ .../rp2/RPI_PICO2_W/webrepl.pyi | 16 + .../rp2/RPI_PICO2_W/webrepl_setup.py | 105 ++ .../rp2/RPI_PICO2_W/webrepl_setup.pyi | 10 + .../rp2/RPI_PICO_W/_boot.py | 16 + .../rp2/RPI_PICO_W/_boot.pyi | 4 + .../rp2/RPI_PICO_W/_boot_fat.py | 14 + .../rp2/RPI_PICO_W/_boot_fat.pyi | 3 + .../rp2/RPI_PICO_W/aioble/__init__.py | 32 + .../rp2/RPI_PICO_W/aioble/__init__.pyi | 9 + .../rp2/RPI_PICO_W/aioble/central.py | 305 ++++ .../rp2/RPI_PICO_W/aioble/central.pyi | 70 + .../rp2/RPI_PICO_W/aioble/client.py | 444 +++++ .../rp2/RPI_PICO_W/aioble/client.pyi | 101 ++ .../rp2/RPI_PICO_W/aioble/core.py | 78 + .../rp2/RPI_PICO_W/aioble/core.pyi | 23 + .../rp2/RPI_PICO_W/aioble/device.py | 304 ++++ .../rp2/RPI_PICO_W/aioble/device.pyi | 66 + .../rp2/RPI_PICO_W/aioble/l2cap.py | 214 +++ .../rp2/RPI_PICO_W/aioble/l2cap.pyi | 40 + .../rp2/RPI_PICO_W/aioble/peripheral.py | 176 ++ .../rp2/RPI_PICO_W/aioble/peripheral.pyi | 44 + .../rp2/RPI_PICO_W/aioble/security.py | 175 ++ .../rp2/RPI_PICO_W/aioble/security.pyi | 27 + .../rp2/RPI_PICO_W/aioble/server.py | 336 ++++ .../rp2/RPI_PICO_W/aioble/server.pyi | 101 ++ .../rp2/RPI_PICO_W/dht.py | 47 + .../rp2/RPI_PICO_W/dht.pyi | 15 + .../rp2/RPI_PICO_W/ds18x20.py | 52 + .../rp2/RPI_PICO_W/ds18x20.pyi | 16 + .../rp2/RPI_PICO_W/mip/__init__.py | 187 ++ .../rp2/RPI_PICO_W/mip/__init__.pyi | 15 + .../rp2/RPI_PICO_W/modules.json | 108 ++ .../rp2/RPI_PICO_W/neopixel.py | 46 + .../rp2/RPI_PICO_W/neopixel.pyi | 86 + .../rp2/RPI_PICO_W/ntptime.py | 68 + .../rp2/RPI_PICO_W/ntptime.pyi | 5 + .../rp2/RPI_PICO_W/onewire.py | 92 + .../rp2/RPI_PICO_W/onewire.pyi | 21 + .../rp2/RPI_PICO_W/removed.txt | 2 + .../rp2/RPI_PICO_W/requests/__init__.py | 221 +++ .../rp2/RPI_PICO_W/requests/__init__.pyi | 21 + .../rp2/RPI_PICO_W/ssl.py | 63 + .../rp2/RPI_PICO_W/ssl.pyi | 180 ++ .../rp2/RPI_PICO_W/urequests.py | 8 + .../rp2/RPI_PICO_W/urequests.pyi | 1 + .../rp2/RPI_PICO_W/webrepl.py | 178 ++ .../rp2/RPI_PICO_W/webrepl.pyi | 16 + .../rp2/RPI_PICO_W/webrepl_setup.py | 105 ++ .../rp2/RPI_PICO_W/webrepl_setup.pyi | 10 + .../rp2/SIL_RP2040_SHIM/_boot.py | 16 + .../rp2/SIL_RP2040_SHIM/_boot.pyi | 4 + .../rp2/SIL_RP2040_SHIM/_boot_fat.py | 14 + .../rp2/SIL_RP2040_SHIM/_boot_fat.pyi | 3 + .../rp2/SIL_RP2040_SHIM/dht.py | 47 + .../rp2/SIL_RP2040_SHIM/dht.pyi | 15 + .../rp2/SIL_RP2040_SHIM/ds18x20.py | 52 + .../rp2/SIL_RP2040_SHIM/ds18x20.pyi | 16 + .../rp2/SIL_RP2040_SHIM/mip/__init__.py | 187 ++ .../rp2/SIL_RP2040_SHIM/mip/__init__.pyi | 15 + .../rp2/SIL_RP2040_SHIM/modules.json | 72 + .../rp2/SIL_RP2040_SHIM/neopixel.py | 46 + .../rp2/SIL_RP2040_SHIM/neopixel.pyi | 86 + .../rp2/SIL_RP2040_SHIM/ntptime.py | 68 + .../rp2/SIL_RP2040_SHIM/ntptime.pyi | 5 + .../rp2/SIL_RP2040_SHIM/onewire.py | 92 + .../rp2/SIL_RP2040_SHIM/onewire.pyi | 21 + .../rp2/SIL_RP2040_SHIM/removed.txt | 2 + .../rp2/SIL_RP2040_SHIM/requests/__init__.py | 221 +++ .../rp2/SIL_RP2040_SHIM/requests/__init__.pyi | 21 + .../rp2/SIL_RP2040_SHIM/ssl.py | 63 + .../rp2/SIL_RP2040_SHIM/ssl.pyi | 180 ++ .../rp2/SIL_RP2040_SHIM/urequests.py | 8 + .../rp2/SIL_RP2040_SHIM/urequests.pyi | 1 + .../rp2/SIL_RP2040_SHIM/webrepl.py | 178 ++ .../rp2/SIL_RP2040_SHIM/webrepl.pyi | 16 + .../rp2/SIL_RP2040_SHIM/webrepl_setup.py | 105 ++ .../rp2/SIL_RP2040_SHIM/webrepl_setup.pyi | 10 + .../SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.py | 16 + .../SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.pyi | 4 + .../_boot_fat.py | 14 + .../_boot_fat.pyi | 3 + .../SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.py | 47 + .../SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.pyi | 15 + .../ds18x20.py | 52 + .../ds18x20.pyi | 16 + .../modules.json | 48 + .../neopixel.py | 46 + .../neopixel.pyi | 86 + .../onewire.py | 92 + .../onewire.pyi | 21 + .../removed.txt | 2 + .../SPARKFUN_IOTNODE_LORAWAN_RP2350/sdcard.py | 306 ++++ .../sdcard.pyi | 31 + .../rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.py | 16 + .../rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.pyi | 4 + .../SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.py | 14 + .../SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.pyi | 3 + .../aioble/__init__.py | 32 + .../aioble/__init__.pyi | 9 + .../aioble/central.py | 305 ++++ .../aioble/central.pyi | 70 + .../aioble/client.py | 444 +++++ .../aioble/client.pyi | 101 ++ .../aioble/core.py | 78 + .../aioble/core.pyi | 23 + .../aioble/device.py | 304 ++++ .../aioble/device.pyi | 66 + .../aioble/l2cap.py | 214 +++ .../aioble/l2cap.pyi | 40 + .../aioble/peripheral.py | 176 ++ .../aioble/peripheral.pyi | 44 + .../aioble/security.py | 175 ++ .../aioble/security.pyi | 27 + .../aioble/server.py | 336 ++++ .../aioble/server.pyi | 101 ++ .../rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.py | 47 + .../rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.pyi | 15 + .../SPARKFUN_IOTREDBOARD_RP2350/ds18x20.py | 52 + .../SPARKFUN_IOTREDBOARD_RP2350/ds18x20.pyi | 16 + .../mip/__init__.py | 187 ++ .../mip/__init__.pyi | 15 + .../SPARKFUN_IOTREDBOARD_RP2350/modules.json | 112 ++ .../SPARKFUN_IOTREDBOARD_RP2350/neopixel.py | 46 + .../SPARKFUN_IOTREDBOARD_RP2350/neopixel.pyi | 86 + .../SPARKFUN_IOTREDBOARD_RP2350/ntptime.py | 68 + .../SPARKFUN_IOTREDBOARD_RP2350/ntptime.pyi | 5 + .../SPARKFUN_IOTREDBOARD_RP2350/onewire.py | 92 + .../SPARKFUN_IOTREDBOARD_RP2350/onewire.pyi | 21 + .../SPARKFUN_IOTREDBOARD_RP2350/removed.txt | 2 + .../requests/__init__.py | 221 +++ .../requests/__init__.pyi | 21 + .../rp2/SPARKFUN_IOTREDBOARD_RP2350/sdcard.py | 306 ++++ .../SPARKFUN_IOTREDBOARD_RP2350/sdcard.pyi | 31 + .../rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.py | 63 + .../rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.pyi | 180 ++ .../SPARKFUN_IOTREDBOARD_RP2350/urequests.py | 8 + .../SPARKFUN_IOTREDBOARD_RP2350/urequests.pyi | 1 + .../SPARKFUN_IOTREDBOARD_RP2350/webrepl.py | 178 ++ .../SPARKFUN_IOTREDBOARD_RP2350/webrepl.pyi | 16 + .../webrepl_setup.py | 105 ++ .../webrepl_setup.pyi | 10 + .../rp2/SPARKFUN_THINGPLUS_RP2350/_boot.py | 16 + .../rp2/SPARKFUN_THINGPLUS_RP2350/_boot.pyi | 4 + .../SPARKFUN_THINGPLUS_RP2350/_boot_fat.py | 14 + .../SPARKFUN_THINGPLUS_RP2350/_boot_fat.pyi | 3 + .../aioble/__init__.py | 32 + .../aioble/__init__.pyi | 9 + .../aioble/central.py | 305 ++++ .../aioble/central.pyi | 70 + .../aioble/client.py | 444 +++++ .../aioble/client.pyi | 101 ++ .../SPARKFUN_THINGPLUS_RP2350/aioble/core.py | 78 + .../SPARKFUN_THINGPLUS_RP2350/aioble/core.pyi | 23 + .../aioble/device.py | 304 ++++ .../aioble/device.pyi | 66 + .../SPARKFUN_THINGPLUS_RP2350/aioble/l2cap.py | 214 +++ .../aioble/l2cap.pyi | 40 + .../aioble/peripheral.py | 176 ++ .../aioble/peripheral.pyi | 44 + .../aioble/security.py | 175 ++ .../aioble/security.pyi | 27 + .../aioble/server.py | 336 ++++ .../aioble/server.pyi | 101 ++ .../rp2/SPARKFUN_THINGPLUS_RP2350/dht.py | 47 + .../rp2/SPARKFUN_THINGPLUS_RP2350/dht.pyi | 15 + .../rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.py | 52 + .../rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.pyi | 16 + .../SPARKFUN_THINGPLUS_RP2350/mip/__init__.py | 187 ++ .../mip/__init__.pyi | 15 + .../SPARKFUN_THINGPLUS_RP2350/modules.json | 108 ++ .../rp2/SPARKFUN_THINGPLUS_RP2350/neopixel.py | 46 + .../SPARKFUN_THINGPLUS_RP2350/neopixel.pyi | 86 + .../rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.py | 68 + .../rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.pyi | 5 + .../rp2/SPARKFUN_THINGPLUS_RP2350/onewire.py | 92 + .../rp2/SPARKFUN_THINGPLUS_RP2350/onewire.pyi | 21 + .../rp2/SPARKFUN_THINGPLUS_RP2350/removed.txt | 2 + .../requests/__init__.py | 221 +++ .../requests/__init__.pyi | 21 + .../rp2/SPARKFUN_THINGPLUS_RP2350/ssl.py | 63 + .../rp2/SPARKFUN_THINGPLUS_RP2350/ssl.pyi | 180 ++ .../SPARKFUN_THINGPLUS_RP2350/urequests.py | 8 + .../SPARKFUN_THINGPLUS_RP2350/urequests.pyi | 1 + .../rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.py | 178 ++ .../rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.pyi | 16 + .../webrepl_setup.py | 105 ++ .../webrepl_setup.pyi | 10 + .../rp2/SPARKFUN_XRP_CONTROLLER/_boot.py | 16 + .../rp2/SPARKFUN_XRP_CONTROLLER/_boot.pyi | 4 + .../rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.py | 14 + .../rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.pyi | 3 + .../aioble/__init__.py | 32 + .../aioble/__init__.pyi | 9 + .../SPARKFUN_XRP_CONTROLLER/aioble/central.py | 305 ++++ .../aioble/central.pyi | 70 + .../SPARKFUN_XRP_CONTROLLER/aioble/client.py | 444 +++++ .../SPARKFUN_XRP_CONTROLLER/aioble/client.pyi | 101 ++ .../SPARKFUN_XRP_CONTROLLER/aioble/core.py | 78 + .../SPARKFUN_XRP_CONTROLLER/aioble/core.pyi | 23 + .../SPARKFUN_XRP_CONTROLLER/aioble/device.py | 304 ++++ .../SPARKFUN_XRP_CONTROLLER/aioble/device.pyi | 66 + .../SPARKFUN_XRP_CONTROLLER/aioble/l2cap.py | 214 +++ .../SPARKFUN_XRP_CONTROLLER/aioble/l2cap.pyi | 40 + .../aioble/peripheral.py | 176 ++ .../aioble/peripheral.pyi | 44 + .../aioble/security.py | 175 ++ .../aioble/security.pyi | 27 + .../SPARKFUN_XRP_CONTROLLER/aioble/server.py | 336 ++++ .../SPARKFUN_XRP_CONTROLLER/aioble/server.pyi | 101 ++ .../rp2/SPARKFUN_XRP_CONTROLLER/dht.py | 47 + .../rp2/SPARKFUN_XRP_CONTROLLER/dht.pyi | 15 + .../rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.py | 52 + .../rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.pyi | 16 + .../SPARKFUN_XRP_CONTROLLER/mip/__init__.py | 187 ++ .../SPARKFUN_XRP_CONTROLLER/mip/__init__.pyi | 15 + .../rp2/SPARKFUN_XRP_CONTROLLER/modules.json | 108 ++ .../rp2/SPARKFUN_XRP_CONTROLLER/neopixel.py | 46 + .../rp2/SPARKFUN_XRP_CONTROLLER/neopixel.pyi | 86 + .../rp2/SPARKFUN_XRP_CONTROLLER/ntptime.py | 68 + .../rp2/SPARKFUN_XRP_CONTROLLER/ntptime.pyi | 5 + .../rp2/SPARKFUN_XRP_CONTROLLER/onewire.py | 92 + .../rp2/SPARKFUN_XRP_CONTROLLER/onewire.pyi | 21 + .../rp2/SPARKFUN_XRP_CONTROLLER/removed.txt | 2 + .../requests/__init__.py | 221 +++ .../requests/__init__.pyi | 21 + .../rp2/SPARKFUN_XRP_CONTROLLER/ssl.py | 63 + .../rp2/SPARKFUN_XRP_CONTROLLER/ssl.pyi | 180 ++ .../rp2/SPARKFUN_XRP_CONTROLLER/urequests.py | 8 + .../rp2/SPARKFUN_XRP_CONTROLLER/urequests.pyi | 1 + .../rp2/SPARKFUN_XRP_CONTROLLER/webrepl.py | 178 ++ .../rp2/SPARKFUN_XRP_CONTROLLER/webrepl.pyi | 16 + .../SPARKFUN_XRP_CONTROLLER/webrepl_setup.py | 105 ++ .../SPARKFUN_XRP_CONTROLLER/webrepl_setup.pyi | 10 + .../rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot.py | 16 + .../SPARKFUN_XRP_CONTROLLER_BETA/_boot.pyi | 4 + .../SPARKFUN_XRP_CONTROLLER_BETA/_boot_fat.py | 14 + .../_boot_fat.pyi | 3 + .../aioble/__init__.py | 32 + .../aioble/__init__.pyi | 9 + .../aioble/central.py | 305 ++++ .../aioble/central.pyi | 70 + .../aioble/client.py | 444 +++++ .../aioble/client.pyi | 101 ++ .../aioble/core.py | 78 + .../aioble/core.pyi | 23 + .../aioble/device.py | 304 ++++ .../aioble/device.pyi | 66 + .../aioble/l2cap.py | 214 +++ .../aioble/l2cap.pyi | 40 + .../aioble/peripheral.py | 176 ++ .../aioble/peripheral.pyi | 44 + .../aioble/security.py | 175 ++ .../aioble/security.pyi | 27 + .../aioble/server.py | 336 ++++ .../aioble/server.pyi | 101 ++ .../rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.py | 47 + .../rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.pyi | 15 + .../SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.py | 52 + .../SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.pyi | 16 + .../mip/__init__.py | 187 ++ .../mip/__init__.pyi | 15 + .../SPARKFUN_XRP_CONTROLLER_BETA/modules.json | 108 ++ .../SPARKFUN_XRP_CONTROLLER_BETA/neopixel.py | 46 + .../SPARKFUN_XRP_CONTROLLER_BETA/neopixel.pyi | 86 + .../SPARKFUN_XRP_CONTROLLER_BETA/ntptime.py | 68 + .../SPARKFUN_XRP_CONTROLLER_BETA/ntptime.pyi | 5 + .../SPARKFUN_XRP_CONTROLLER_BETA/onewire.py | 92 + .../SPARKFUN_XRP_CONTROLLER_BETA/onewire.pyi | 21 + .../SPARKFUN_XRP_CONTROLLER_BETA/removed.txt | 2 + .../requests/__init__.py | 221 +++ .../requests/__init__.pyi | 21 + .../rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.py | 63 + .../rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.pyi | 180 ++ .../SPARKFUN_XRP_CONTROLLER_BETA/urequests.py | 8 + .../urequests.pyi | 1 + .../SPARKFUN_XRP_CONTROLLER_BETA/webrepl.py | 178 ++ .../SPARKFUN_XRP_CONTROLLER_BETA/webrepl.pyi | 16 + .../webrepl_setup.py | 105 ++ .../webrepl_setup.pyi | 10 + .../rp2/W5100S_EVB_PICO/_boot.py | 16 + .../rp2/W5100S_EVB_PICO/_boot.pyi | 4 + .../rp2/W5100S_EVB_PICO/_boot_fat.py | 14 + .../rp2/W5100S_EVB_PICO/_boot_fat.pyi | 3 + .../rp2/W5100S_EVB_PICO/dht.py | 47 + .../rp2/W5100S_EVB_PICO/dht.pyi | 15 + .../rp2/W5100S_EVB_PICO/ds18x20.py | 52 + .../rp2/W5100S_EVB_PICO/ds18x20.pyi | 16 + .../rp2/W5100S_EVB_PICO/mip/__init__.py | 187 ++ .../rp2/W5100S_EVB_PICO/mip/__init__.pyi | 15 + .../rp2/W5100S_EVB_PICO/modules.json | 72 + .../rp2/W5100S_EVB_PICO/neopixel.py | 46 + .../rp2/W5100S_EVB_PICO/neopixel.pyi | 86 + .../rp2/W5100S_EVB_PICO/ntptime.py | 68 + .../rp2/W5100S_EVB_PICO/ntptime.pyi | 5 + .../rp2/W5100S_EVB_PICO/onewire.py | 92 + .../rp2/W5100S_EVB_PICO/onewire.pyi | 21 + .../rp2/W5100S_EVB_PICO/removed.txt | 2 + .../rp2/W5100S_EVB_PICO/requests/__init__.py | 221 +++ .../rp2/W5100S_EVB_PICO/requests/__init__.pyi | 21 + .../rp2/W5100S_EVB_PICO/ssl.py | 63 + .../rp2/W5100S_EVB_PICO/ssl.pyi | 180 ++ .../rp2/W5100S_EVB_PICO/urequests.py | 8 + .../rp2/W5100S_EVB_PICO/urequests.pyi | 1 + .../rp2/W5100S_EVB_PICO/webrepl.py | 178 ++ .../rp2/W5100S_EVB_PICO/webrepl.pyi | 16 + .../rp2/W5100S_EVB_PICO/webrepl_setup.py | 105 ++ .../rp2/W5100S_EVB_PICO/webrepl_setup.pyi | 10 + .../rp2/W5500_EVB_PICO/_boot.py | 16 + .../rp2/W5500_EVB_PICO/_boot.pyi | 4 + .../rp2/W5500_EVB_PICO/_boot_fat.py | 14 + .../rp2/W5500_EVB_PICO/_boot_fat.pyi | 3 + .../rp2/W5500_EVB_PICO/dht.py | 47 + .../rp2/W5500_EVB_PICO/dht.pyi | 15 + .../rp2/W5500_EVB_PICO/ds18x20.py | 52 + .../rp2/W5500_EVB_PICO/ds18x20.pyi | 16 + .../rp2/W5500_EVB_PICO/mip/__init__.py | 187 ++ .../rp2/W5500_EVB_PICO/mip/__init__.pyi | 15 + .../rp2/W5500_EVB_PICO/modules.json | 72 + .../rp2/W5500_EVB_PICO/neopixel.py | 46 + .../rp2/W5500_EVB_PICO/neopixel.pyi | 86 + .../rp2/W5500_EVB_PICO/ntptime.py | 68 + .../rp2/W5500_EVB_PICO/ntptime.pyi | 5 + .../rp2/W5500_EVB_PICO/onewire.py | 92 + .../rp2/W5500_EVB_PICO/onewire.pyi | 21 + .../rp2/W5500_EVB_PICO/removed.txt | 2 + .../rp2/W5500_EVB_PICO/requests/__init__.py | 221 +++ .../rp2/W5500_EVB_PICO/requests/__init__.pyi | 21 + .../rp2/W5500_EVB_PICO/ssl.py | 63 + .../rp2/W5500_EVB_PICO/ssl.pyi | 180 ++ .../rp2/W5500_EVB_PICO/urequests.py | 8 + .../rp2/W5500_EVB_PICO/urequests.pyi | 1 + .../rp2/W5500_EVB_PICO/webrepl.py | 178 ++ .../rp2/W5500_EVB_PICO/webrepl.pyi | 16 + .../rp2/W5500_EVB_PICO/webrepl_setup.py | 105 ++ .../rp2/W5500_EVB_PICO/webrepl_setup.pyi | 10 + .../rp2/WEACTSTUDIO/_boot.py | 16 + .../rp2/WEACTSTUDIO/_boot.pyi | 4 + .../rp2/WEACTSTUDIO/_boot_fat.py | 14 + .../rp2/WEACTSTUDIO/_boot_fat.pyi | 3 + .../rp2/WEACTSTUDIO/board.py | 4 + .../rp2/WEACTSTUDIO/board.pyi | 4 + .../rp2/WEACTSTUDIO/dht.py | 47 + .../rp2/WEACTSTUDIO/dht.pyi | 15 + .../rp2/WEACTSTUDIO/ds18x20.py | 52 + .../rp2/WEACTSTUDIO/ds18x20.pyi | 16 + .../rp2/WEACTSTUDIO/modules.json | 48 + .../rp2/WEACTSTUDIO/neopixel.py | 46 + .../rp2/WEACTSTUDIO/neopixel.pyi | 86 + .../rp2/WEACTSTUDIO/onewire.py | 92 + .../rp2/WEACTSTUDIO/onewire.pyi | 21 + .../rp2/WEACTSTUDIO/removed.txt | 2 + .../rp2/WEACTSTUDIO_RP2350B_CORE/_boot.py | 16 + .../rp2/WEACTSTUDIO_RP2350B_CORE/_boot.pyi | 4 + .../rp2/WEACTSTUDIO_RP2350B_CORE/_boot_fat.py | 14 + .../WEACTSTUDIO_RP2350B_CORE/_boot_fat.pyi | 3 + .../rp2/WEACTSTUDIO_RP2350B_CORE/dht.py | 47 + .../rp2/WEACTSTUDIO_RP2350B_CORE/dht.pyi | 15 + .../rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.py | 52 + .../rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.pyi | 16 + .../rp2/WEACTSTUDIO_RP2350B_CORE/modules.json | 44 + .../rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.py | 46 + .../rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.pyi | 86 + .../rp2/WEACTSTUDIO_RP2350B_CORE/onewire.py | 92 + .../rp2/WEACTSTUDIO_RP2350B_CORE/onewire.pyi | 21 + .../rp2/WEACTSTUDIO_RP2350B_CORE/removed.txt | 2 + .../samd/GENERIC/_boot.py | 21 + .../samd/GENERIC/_boot.pyi | 5 + .../samd/GENERIC/dht.py | 47 + .../samd/GENERIC/dht.pyi | 15 + .../samd/GENERIC/ds18x20.py | 52 + .../samd/GENERIC/ds18x20.pyi | 16 + .../samd/GENERIC/modules.json | 36 + .../samd/GENERIC/onewire.py | 92 + .../samd/GENERIC/onewire.pyi | 21 + .../samd/GENERIC/removed.txt | 2 + .../stm32/ARDUINO_GIGA/aioble/__init__.py | 32 + .../stm32/ARDUINO_GIGA/aioble/__init__.pyi | 9 + .../stm32/ARDUINO_GIGA/aioble/central.py | 305 ++++ .../stm32/ARDUINO_GIGA/aioble/central.pyi | 70 + .../stm32/ARDUINO_GIGA/aioble/client.py | 444 +++++ .../stm32/ARDUINO_GIGA/aioble/client.pyi | 101 ++ .../stm32/ARDUINO_GIGA/aioble/core.py | 78 + .../stm32/ARDUINO_GIGA/aioble/core.pyi | 23 + .../stm32/ARDUINO_GIGA/aioble/device.py | 304 ++++ .../stm32/ARDUINO_GIGA/aioble/device.pyi | 66 + .../stm32/ARDUINO_GIGA/aioble/l2cap.py | 214 +++ .../stm32/ARDUINO_GIGA/aioble/l2cap.pyi | 40 + .../stm32/ARDUINO_GIGA/aioble/peripheral.py | 176 ++ .../stm32/ARDUINO_GIGA/aioble/peripheral.pyi | 44 + .../stm32/ARDUINO_GIGA/aioble/security.py | 175 ++ .../stm32/ARDUINO_GIGA/aioble/security.pyi | 27 + .../stm32/ARDUINO_GIGA/aioble/server.py | 336 ++++ .../stm32/ARDUINO_GIGA/aioble/server.pyi | 101 ++ .../stm32/ARDUINO_GIGA/cbor2/__init__.py | 32 + .../stm32/ARDUINO_GIGA/cbor2/__init__.pyi | 2 + .../stm32/ARDUINO_GIGA/cbor2/_decoder.py | 254 +++ .../stm32/ARDUINO_GIGA/cbor2/_decoder.pyi | 66 + .../stm32/ARDUINO_GIGA/cbor2/_encoder.py | 182 ++ .../stm32/ARDUINO_GIGA/cbor2/_encoder.pyi | 54 + .../stm32/ARDUINO_GIGA/dht.py | 47 + .../stm32/ARDUINO_GIGA/dht.pyi | 15 + .../stm32/ARDUINO_GIGA/logging.py | 253 +++ .../stm32/ARDUINO_GIGA/logging.pyi | 86 + .../stm32/ARDUINO_GIGA/mip/__init__.py | 187 ++ .../stm32/ARDUINO_GIGA/mip/__init__.pyi | 15 + .../stm32/ARDUINO_GIGA/modules.json | 140 ++ .../stm32/ARDUINO_GIGA/msgpack.py | 860 ++++++++++ .../stm32/ARDUINO_GIGA/msgpack.pyi | 278 +++ .../stm32/ARDUINO_GIGA/msgpackrpc.py | 202 +++ .../stm32/ARDUINO_GIGA/msgpackrpc.pyi | 68 + .../stm32/ARDUINO_GIGA/ntptime.py | 68 + .../stm32/ARDUINO_GIGA/ntptime.pyi | 5 + .../stm32/ARDUINO_GIGA/onewire.py | 92 + .../stm32/ARDUINO_GIGA/onewire.pyi | 21 + .../stm32/ARDUINO_GIGA/removed.txt | 2 + .../stm32/ARDUINO_GIGA/requests/__init__.py | 221 +++ .../stm32/ARDUINO_GIGA/requests/__init__.pyi | 21 + .../stm32/ARDUINO_GIGA/senml/__init__.py | 29 + .../stm32/ARDUINO_GIGA/senml/__init__.pyi | 4 + .../stm32/ARDUINO_GIGA/senml/senml_base.py | 30 + .../stm32/ARDUINO_GIGA/senml/senml_base.pyi | 4 + .../stm32/ARDUINO_GIGA/senml/senml_pack.py | 358 ++++ .../stm32/ARDUINO_GIGA/senml/senml_pack.pyi | 143 ++ .../stm32/ARDUINO_GIGA/senml/senml_record.py | 240 +++ .../stm32/ARDUINO_GIGA/senml/senml_record.pyi | 104 ++ .../stm32/ARDUINO_GIGA/senml/senml_unit.py | 89 + .../stm32/ARDUINO_GIGA/senml/senml_unit.pyi | 5 + .../stm32/ARDUINO_GIGA/ssl.py | 63 + .../stm32/ARDUINO_GIGA/ssl.pyi | 180 ++ .../stm32/ARDUINO_GIGA/time.py | 79 + .../stm32/ARDUINO_GIGA/time.pyi | 59 + .../stm32/ARDUINO_GIGA/urequests.py | 8 + .../stm32/ARDUINO_GIGA/urequests.pyi | 1 + .../stm32/ARDUINO_GIGA/webrepl.py | 178 ++ .../stm32/ARDUINO_GIGA/webrepl.pyi | 16 + .../stm32/ARDUINO_GIGA/webrepl_setup.py | 105 ++ .../stm32/ARDUINO_GIGA/webrepl_setup.pyi | 10 + .../ARDUINO_NICLA_VISION/aioble/__init__.py | 32 + .../ARDUINO_NICLA_VISION/aioble/__init__.pyi | 9 + .../ARDUINO_NICLA_VISION/aioble/central.py | 305 ++++ .../ARDUINO_NICLA_VISION/aioble/central.pyi | 70 + .../ARDUINO_NICLA_VISION/aioble/client.py | 444 +++++ .../ARDUINO_NICLA_VISION/aioble/client.pyi | 101 ++ .../stm32/ARDUINO_NICLA_VISION/aioble/core.py | 78 + .../ARDUINO_NICLA_VISION/aioble/core.pyi | 23 + .../ARDUINO_NICLA_VISION/aioble/device.py | 304 ++++ .../ARDUINO_NICLA_VISION/aioble/device.pyi | 66 + .../ARDUINO_NICLA_VISION/aioble/l2cap.py | 214 +++ .../ARDUINO_NICLA_VISION/aioble/l2cap.pyi | 40 + .../ARDUINO_NICLA_VISION/aioble/peripheral.py | 176 ++ .../aioble/peripheral.pyi | 44 + .../ARDUINO_NICLA_VISION/aioble/security.py | 175 ++ .../ARDUINO_NICLA_VISION/aioble/security.pyi | 27 + .../ARDUINO_NICLA_VISION/aioble/server.py | 336 ++++ .../ARDUINO_NICLA_VISION/aioble/server.pyi | 101 ++ .../ARDUINO_NICLA_VISION/cbor2/__init__.py | 32 + .../ARDUINO_NICLA_VISION/cbor2/__init__.pyi | 2 + .../ARDUINO_NICLA_VISION/cbor2/_decoder.py | 254 +++ .../ARDUINO_NICLA_VISION/cbor2/_decoder.pyi | 66 + .../ARDUINO_NICLA_VISION/cbor2/_encoder.py | 182 ++ .../ARDUINO_NICLA_VISION/cbor2/_encoder.pyi | 54 + .../stm32/ARDUINO_NICLA_VISION/dht.py | 47 + .../stm32/ARDUINO_NICLA_VISION/dht.pyi | 15 + .../stm32/ARDUINO_NICLA_VISION/logging.py | 253 +++ .../stm32/ARDUINO_NICLA_VISION/logging.pyi | 86 + .../ARDUINO_NICLA_VISION/mip/__init__.py | 187 ++ .../ARDUINO_NICLA_VISION/mip/__init__.pyi | 15 + .../stm32/ARDUINO_NICLA_VISION/modules.json | 152 ++ .../stm32/ARDUINO_NICLA_VISION/msgpack.py | 860 ++++++++++ .../stm32/ARDUINO_NICLA_VISION/msgpack.pyi | 278 +++ .../stm32/ARDUINO_NICLA_VISION/msgpackrpc.py | 202 +++ .../stm32/ARDUINO_NICLA_VISION/msgpackrpc.pyi | 68 + .../stm32/ARDUINO_NICLA_VISION/ntptime.py | 68 + .../stm32/ARDUINO_NICLA_VISION/ntptime.pyi | 5 + .../stm32/ARDUINO_NICLA_VISION/onewire.py | 92 + .../stm32/ARDUINO_NICLA_VISION/onewire.pyi | 21 + .../stm32/ARDUINO_NICLA_VISION/removed.txt | 2 + .../ARDUINO_NICLA_VISION/requests/__init__.py | 221 +++ .../requests/__init__.pyi | 21 + .../ARDUINO_NICLA_VISION/se05x/__init__.py | 22 + .../ARDUINO_NICLA_VISION/se05x/__init__.pyi | 19 + .../ARDUINO_NICLA_VISION/se05x/iso7816.py | 382 +++++ .../ARDUINO_NICLA_VISION/se05x/iso7816.pyi | 62 + .../stm32/ARDUINO_NICLA_VISION/se05x/se05x.py | 250 +++ .../ARDUINO_NICLA_VISION/se05x/se05x.pyi | 96 ++ .../ARDUINO_NICLA_VISION/senml/__init__.py | 29 + .../ARDUINO_NICLA_VISION/senml/__init__.pyi | 4 + .../ARDUINO_NICLA_VISION/senml/senml_base.py | 30 + .../ARDUINO_NICLA_VISION/senml/senml_base.pyi | 4 + .../ARDUINO_NICLA_VISION/senml/senml_pack.py | 358 ++++ .../ARDUINO_NICLA_VISION/senml/senml_pack.pyi | 143 ++ .../senml/senml_record.py | 240 +++ .../senml/senml_record.pyi | 104 ++ .../ARDUINO_NICLA_VISION/senml/senml_unit.py | 89 + .../ARDUINO_NICLA_VISION/senml/senml_unit.pyi | 5 + .../stm32/ARDUINO_NICLA_VISION/ssl.py | 63 + .../stm32/ARDUINO_NICLA_VISION/ssl.pyi | 180 ++ .../stm32/ARDUINO_NICLA_VISION/time.py | 79 + .../stm32/ARDUINO_NICLA_VISION/time.pyi | 59 + .../stm32/ARDUINO_NICLA_VISION/urequests.py | 8 + .../stm32/ARDUINO_NICLA_VISION/urequests.pyi | 1 + .../stm32/ARDUINO_NICLA_VISION/webrepl.py | 178 ++ .../stm32/ARDUINO_NICLA_VISION/webrepl.pyi | 16 + .../ARDUINO_NICLA_VISION/webrepl_setup.py | 105 ++ .../ARDUINO_NICLA_VISION/webrepl_setup.pyi | 10 + .../stm32/ARDUINO_OPTA/aioble/__init__.py | 32 + .../stm32/ARDUINO_OPTA/aioble/__init__.pyi | 9 + .../stm32/ARDUINO_OPTA/aioble/central.py | 305 ++++ .../stm32/ARDUINO_OPTA/aioble/central.pyi | 70 + .../stm32/ARDUINO_OPTA/aioble/client.py | 444 +++++ .../stm32/ARDUINO_OPTA/aioble/client.pyi | 101 ++ .../stm32/ARDUINO_OPTA/aioble/core.py | 78 + .../stm32/ARDUINO_OPTA/aioble/core.pyi | 23 + .../stm32/ARDUINO_OPTA/aioble/device.py | 304 ++++ .../stm32/ARDUINO_OPTA/aioble/device.pyi | 66 + .../stm32/ARDUINO_OPTA/aioble/l2cap.py | 214 +++ .../stm32/ARDUINO_OPTA/aioble/l2cap.pyi | 40 + .../stm32/ARDUINO_OPTA/aioble/peripheral.py | 176 ++ .../stm32/ARDUINO_OPTA/aioble/peripheral.pyi | 44 + .../stm32/ARDUINO_OPTA/aioble/security.py | 175 ++ .../stm32/ARDUINO_OPTA/aioble/security.pyi | 27 + .../stm32/ARDUINO_OPTA/aioble/server.py | 336 ++++ .../stm32/ARDUINO_OPTA/aioble/server.pyi | 101 ++ .../stm32/ARDUINO_OPTA/cbor2/__init__.py | 32 + .../stm32/ARDUINO_OPTA/cbor2/__init__.pyi | 2 + .../stm32/ARDUINO_OPTA/cbor2/_decoder.py | 254 +++ .../stm32/ARDUINO_OPTA/cbor2/_decoder.pyi | 66 + .../stm32/ARDUINO_OPTA/cbor2/_encoder.py | 182 ++ .../stm32/ARDUINO_OPTA/cbor2/_encoder.pyi | 54 + .../stm32/ARDUINO_OPTA/dht.py | 47 + .../stm32/ARDUINO_OPTA/dht.pyi | 15 + .../stm32/ARDUINO_OPTA/logging.py | 253 +++ .../stm32/ARDUINO_OPTA/logging.pyi | 86 + .../stm32/ARDUINO_OPTA/mip/__init__.py | 187 ++ .../stm32/ARDUINO_OPTA/mip/__init__.pyi | 15 + .../stm32/ARDUINO_OPTA/modules.json | 144 ++ .../stm32/ARDUINO_OPTA/msgpack.py | 860 ++++++++++ .../stm32/ARDUINO_OPTA/msgpack.pyi | 278 +++ .../stm32/ARDUINO_OPTA/msgpackrpc.py | 202 +++ .../stm32/ARDUINO_OPTA/msgpackrpc.pyi | 68 + .../stm32/ARDUINO_OPTA/ntptime.py | 68 + .../stm32/ARDUINO_OPTA/ntptime.pyi | 5 + .../stm32/ARDUINO_OPTA/onewire.py | 92 + .../stm32/ARDUINO_OPTA/onewire.pyi | 21 + .../stm32/ARDUINO_OPTA/opta.py | 444 +++++ .../stm32/ARDUINO_OPTA/opta.pyi | 164 ++ .../stm32/ARDUINO_OPTA/removed.txt | 2 + .../stm32/ARDUINO_OPTA/requests/__init__.py | 221 +++ .../stm32/ARDUINO_OPTA/requests/__init__.pyi | 21 + .../stm32/ARDUINO_OPTA/senml/__init__.py | 29 + .../stm32/ARDUINO_OPTA/senml/__init__.pyi | 4 + .../stm32/ARDUINO_OPTA/senml/senml_base.py | 30 + .../stm32/ARDUINO_OPTA/senml/senml_base.pyi | 4 + .../stm32/ARDUINO_OPTA/senml/senml_pack.py | 358 ++++ .../stm32/ARDUINO_OPTA/senml/senml_pack.pyi | 143 ++ .../stm32/ARDUINO_OPTA/senml/senml_record.py | 240 +++ .../stm32/ARDUINO_OPTA/senml/senml_record.pyi | 104 ++ .../stm32/ARDUINO_OPTA/senml/senml_unit.py | 89 + .../stm32/ARDUINO_OPTA/senml/senml_unit.pyi | 5 + .../stm32/ARDUINO_OPTA/ssl.py | 63 + .../stm32/ARDUINO_OPTA/ssl.pyi | 180 ++ .../stm32/ARDUINO_OPTA/time.py | 79 + .../stm32/ARDUINO_OPTA/time.pyi | 59 + .../stm32/ARDUINO_OPTA/urequests.py | 8 + .../stm32/ARDUINO_OPTA/urequests.pyi | 1 + .../stm32/ARDUINO_OPTA/webrepl.py | 178 ++ .../stm32/ARDUINO_OPTA/webrepl.pyi | 16 + .../stm32/ARDUINO_OPTA/webrepl_setup.py | 105 ++ .../stm32/ARDUINO_OPTA/webrepl_setup.pyi | 10 + .../ARDUINO_PORTENTA_H7/aioble/__init__.py | 32 + .../ARDUINO_PORTENTA_H7/aioble/__init__.pyi | 9 + .../ARDUINO_PORTENTA_H7/aioble/central.py | 305 ++++ .../ARDUINO_PORTENTA_H7/aioble/central.pyi | 70 + .../ARDUINO_PORTENTA_H7/aioble/client.py | 444 +++++ .../ARDUINO_PORTENTA_H7/aioble/client.pyi | 101 ++ .../stm32/ARDUINO_PORTENTA_H7/aioble/core.py | 78 + .../stm32/ARDUINO_PORTENTA_H7/aioble/core.pyi | 23 + .../ARDUINO_PORTENTA_H7/aioble/device.py | 304 ++++ .../ARDUINO_PORTENTA_H7/aioble/device.pyi | 66 + .../stm32/ARDUINO_PORTENTA_H7/aioble/l2cap.py | 214 +++ .../ARDUINO_PORTENTA_H7/aioble/l2cap.pyi | 40 + .../ARDUINO_PORTENTA_H7/aioble/peripheral.py | 176 ++ .../ARDUINO_PORTENTA_H7/aioble/peripheral.pyi | 44 + .../ARDUINO_PORTENTA_H7/aioble/security.py | 175 ++ .../ARDUINO_PORTENTA_H7/aioble/security.pyi | 27 + .../ARDUINO_PORTENTA_H7/aioble/server.py | 336 ++++ .../ARDUINO_PORTENTA_H7/aioble/server.pyi | 101 ++ .../ARDUINO_PORTENTA_H7/cbor2/__init__.py | 32 + .../ARDUINO_PORTENTA_H7/cbor2/__init__.pyi | 2 + .../ARDUINO_PORTENTA_H7/cbor2/_decoder.py | 254 +++ .../ARDUINO_PORTENTA_H7/cbor2/_decoder.pyi | 66 + .../ARDUINO_PORTENTA_H7/cbor2/_encoder.py | 182 ++ .../ARDUINO_PORTENTA_H7/cbor2/_encoder.pyi | 54 + .../stm32/ARDUINO_PORTENTA_H7/cmwx1.py | 357 ++++ .../stm32/ARDUINO_PORTENTA_H7/cmwx1.pyi | 81 + .../stm32/ARDUINO_PORTENTA_H7/dht.py | 47 + .../stm32/ARDUINO_PORTENTA_H7/dht.pyi | 15 + .../stm32/ARDUINO_PORTENTA_H7/logging.py | 253 +++ .../stm32/ARDUINO_PORTENTA_H7/logging.pyi | 86 + .../stm32/ARDUINO_PORTENTA_H7/mip/__init__.py | 187 ++ .../ARDUINO_PORTENTA_H7/mip/__init__.pyi | 15 + .../stm32/ARDUINO_PORTENTA_H7/modules.json | 156 ++ .../stm32/ARDUINO_PORTENTA_H7/msgpack.py | 860 ++++++++++ .../stm32/ARDUINO_PORTENTA_H7/msgpack.pyi | 278 +++ .../stm32/ARDUINO_PORTENTA_H7/msgpackrpc.py | 202 +++ .../stm32/ARDUINO_PORTENTA_H7/msgpackrpc.pyi | 68 + .../stm32/ARDUINO_PORTENTA_H7/ntptime.py | 68 + .../stm32/ARDUINO_PORTENTA_H7/ntptime.pyi | 5 + .../stm32/ARDUINO_PORTENTA_H7/onewire.py | 92 + .../stm32/ARDUINO_PORTENTA_H7/onewire.pyi | 21 + .../stm32/ARDUINO_PORTENTA_H7/removed.txt | 2 + .../ARDUINO_PORTENTA_H7/requests/__init__.py | 221 +++ .../ARDUINO_PORTENTA_H7/requests/__init__.pyi | 21 + .../ARDUINO_PORTENTA_H7/se05x/__init__.py | 22 + .../ARDUINO_PORTENTA_H7/se05x/__init__.pyi | 19 + .../ARDUINO_PORTENTA_H7/se05x/iso7816.py | 382 +++++ .../ARDUINO_PORTENTA_H7/se05x/iso7816.pyi | 62 + .../stm32/ARDUINO_PORTENTA_H7/se05x/se05x.py | 250 +++ .../stm32/ARDUINO_PORTENTA_H7/se05x/se05x.pyi | 96 ++ .../ARDUINO_PORTENTA_H7/senml/__init__.py | 29 + .../ARDUINO_PORTENTA_H7/senml/__init__.pyi | 4 + .../ARDUINO_PORTENTA_H7/senml/senml_base.py | 30 + .../ARDUINO_PORTENTA_H7/senml/senml_base.pyi | 4 + .../ARDUINO_PORTENTA_H7/senml/senml_pack.py | 358 ++++ .../ARDUINO_PORTENTA_H7/senml/senml_pack.pyi | 143 ++ .../ARDUINO_PORTENTA_H7/senml/senml_record.py | 240 +++ .../senml/senml_record.pyi | 104 ++ .../ARDUINO_PORTENTA_H7/senml/senml_unit.py | 89 + .../ARDUINO_PORTENTA_H7/senml/senml_unit.pyi | 5 + .../stm32/ARDUINO_PORTENTA_H7/ssl.py | 63 + .../stm32/ARDUINO_PORTENTA_H7/ssl.pyi | 180 ++ .../stm32/ARDUINO_PORTENTA_H7/time.py | 79 + .../stm32/ARDUINO_PORTENTA_H7/time.pyi | 59 + .../stm32/ARDUINO_PORTENTA_H7/urequests.py | 8 + .../stm32/ARDUINO_PORTENTA_H7/urequests.pyi | 1 + .../stm32/ARDUINO_PORTENTA_H7/webrepl.py | 178 ++ .../stm32/ARDUINO_PORTENTA_H7/webrepl.pyi | 16 + .../ARDUINO_PORTENTA_H7/webrepl_setup.py | 105 ++ .../ARDUINO_PORTENTA_H7/webrepl_setup.pyi | 10 + .../GARATRONIC_PYBSTICK26_F411/modules.json | 24 + .../GARATRONIC_PYBSTICK26_F411/ssd1306.py | 164 ++ .../GARATRONIC_PYBSTICK26_F411/ssd1306.pyi | 56 + .../stm32/GENERIC/dht.py | 47 + .../stm32/GENERIC/dht.pyi | 15 + .../stm32/GENERIC/modules.json | 28 + .../stm32/GENERIC/onewire.py | 92 + .../stm32/GENERIC/onewire.pyi | 21 + .../stm32/GENERIC/removed.txt | 2 + .../stm32/LEGO_HUB_NO6/appupdate.py | 65 + .../stm32/LEGO_HUB_NO6/appupdate.pyi | 11 + .../stm32/LEGO_HUB_NO6/dht.py | 47 + .../stm32/LEGO_HUB_NO6/dht.pyi | 15 + .../stm32/LEGO_HUB_NO6/fwupdate.py | 303 ++++ .../stm32/LEGO_HUB_NO6/fwupdate.pyi | 55 + .../stm32/LEGO_HUB_NO6/modules.json | 36 + .../stm32/LEGO_HUB_NO6/onewire.py | 92 + .../stm32/LEGO_HUB_NO6/onewire.pyi | 21 + .../stm32/LEGO_HUB_NO6/removed.txt | 2 + .../stm32/LEGO_HUB_NO7/appupdate.py | 65 + .../stm32/LEGO_HUB_NO7/appupdate.pyi | 11 + .../stm32/LEGO_HUB_NO7/dht.py | 47 + .../stm32/LEGO_HUB_NO7/dht.pyi | 15 + .../stm32/LEGO_HUB_NO7/fwupdate.py | 303 ++++ .../stm32/LEGO_HUB_NO7/fwupdate.pyi | 55 + .../stm32/LEGO_HUB_NO7/modules.json | 36 + .../stm32/LEGO_HUB_NO7/onewire.py | 92 + .../stm32/LEGO_HUB_NO7/onewire.pyi | 21 + .../stm32/LEGO_HUB_NO7/removed.txt | 2 + .../stm32/NUCLEO_F429ZI/dht.py | 47 + .../stm32/NUCLEO_F429ZI/dht.pyi | 15 + .../stm32/NUCLEO_F429ZI/mip/__init__.py | 187 ++ .../stm32/NUCLEO_F429ZI/mip/__init__.pyi | 15 + .../stm32/NUCLEO_F429ZI/modules.json | 56 + .../stm32/NUCLEO_F429ZI/ntptime.py | 68 + .../stm32/NUCLEO_F429ZI/ntptime.pyi | 5 + .../stm32/NUCLEO_F429ZI/onewire.py | 92 + .../stm32/NUCLEO_F429ZI/onewire.pyi | 21 + .../stm32/NUCLEO_F429ZI/removed.txt | 2 + .../stm32/NUCLEO_F429ZI/requests/__init__.py | 221 +++ .../stm32/NUCLEO_F429ZI/requests/__init__.pyi | 21 + .../stm32/NUCLEO_F429ZI/ssl.py | 63 + .../stm32/NUCLEO_F429ZI/ssl.pyi | 180 ++ .../stm32/NUCLEO_F429ZI/urequests.py | 8 + .../stm32/NUCLEO_F429ZI/urequests.pyi | 1 + .../stm32/NUCLEO_F429ZI/webrepl.py | 178 ++ .../stm32/NUCLEO_F429ZI/webrepl.pyi | 16 + .../stm32/NUCLEO_F429ZI/webrepl_setup.py | 105 ++ .../stm32/NUCLEO_F429ZI/webrepl_setup.pyi | 10 + .../stm32/NUCLEO_F439ZI/dht.py | 47 + .../stm32/NUCLEO_F439ZI/dht.pyi | 15 + .../stm32/NUCLEO_F439ZI/mip/__init__.py | 187 ++ .../stm32/NUCLEO_F439ZI/mip/__init__.pyi | 15 + .../stm32/NUCLEO_F439ZI/modules.json | 56 + .../stm32/NUCLEO_F439ZI/ntptime.py | 68 + .../stm32/NUCLEO_F439ZI/ntptime.pyi | 5 + .../stm32/NUCLEO_F439ZI/onewire.py | 92 + .../stm32/NUCLEO_F439ZI/onewire.pyi | 21 + .../stm32/NUCLEO_F439ZI/removed.txt | 2 + .../stm32/NUCLEO_F439ZI/requests/__init__.py | 221 +++ .../stm32/NUCLEO_F439ZI/requests/__init__.pyi | 21 + .../stm32/NUCLEO_F439ZI/ssl.py | 63 + .../stm32/NUCLEO_F439ZI/ssl.pyi | 180 ++ .../stm32/NUCLEO_F439ZI/urequests.py | 8 + .../stm32/NUCLEO_F439ZI/urequests.pyi | 1 + .../stm32/NUCLEO_F439ZI/webrepl.py | 178 ++ .../stm32/NUCLEO_F439ZI/webrepl.pyi | 16 + .../stm32/NUCLEO_F439ZI/webrepl_setup.py | 105 ++ .../stm32/NUCLEO_F439ZI/webrepl_setup.pyi | 10 + .../stm32/NUCLEO_F746ZG/dht.py | 47 + .../stm32/NUCLEO_F746ZG/dht.pyi | 15 + .../stm32/NUCLEO_F746ZG/mip/__init__.py | 187 ++ .../stm32/NUCLEO_F746ZG/mip/__init__.pyi | 15 + .../stm32/NUCLEO_F746ZG/modules.json | 56 + .../stm32/NUCLEO_F746ZG/ntptime.py | 68 + .../stm32/NUCLEO_F746ZG/ntptime.pyi | 5 + .../stm32/NUCLEO_F746ZG/onewire.py | 92 + .../stm32/NUCLEO_F746ZG/onewire.pyi | 21 + .../stm32/NUCLEO_F746ZG/removed.txt | 2 + .../stm32/NUCLEO_F746ZG/requests/__init__.py | 221 +++ .../stm32/NUCLEO_F746ZG/requests/__init__.pyi | 21 + .../stm32/NUCLEO_F746ZG/ssl.py | 63 + .../stm32/NUCLEO_F746ZG/ssl.pyi | 180 ++ .../stm32/NUCLEO_F746ZG/urequests.py | 8 + .../stm32/NUCLEO_F746ZG/urequests.pyi | 1 + .../stm32/NUCLEO_F746ZG/webrepl.py | 178 ++ .../stm32/NUCLEO_F746ZG/webrepl.pyi | 16 + .../stm32/NUCLEO_F746ZG/webrepl_setup.py | 105 ++ .../stm32/NUCLEO_F746ZG/webrepl_setup.pyi | 10 + .../stm32/NUCLEO_F756ZG/dht.py | 47 + .../stm32/NUCLEO_F756ZG/dht.pyi | 15 + .../stm32/NUCLEO_F756ZG/mip/__init__.py | 187 ++ .../stm32/NUCLEO_F756ZG/mip/__init__.pyi | 15 + .../stm32/NUCLEO_F756ZG/modules.json | 56 + .../stm32/NUCLEO_F756ZG/ntptime.py | 68 + .../stm32/NUCLEO_F756ZG/ntptime.pyi | 5 + .../stm32/NUCLEO_F756ZG/onewire.py | 92 + .../stm32/NUCLEO_F756ZG/onewire.pyi | 21 + .../stm32/NUCLEO_F756ZG/removed.txt | 2 + .../stm32/NUCLEO_F756ZG/requests/__init__.py | 221 +++ .../stm32/NUCLEO_F756ZG/requests/__init__.pyi | 21 + .../stm32/NUCLEO_F756ZG/ssl.py | 63 + .../stm32/NUCLEO_F756ZG/ssl.pyi | 180 ++ .../stm32/NUCLEO_F756ZG/urequests.py | 8 + .../stm32/NUCLEO_F756ZG/urequests.pyi | 1 + .../stm32/NUCLEO_F756ZG/webrepl.py | 178 ++ .../stm32/NUCLEO_F756ZG/webrepl.pyi | 16 + .../stm32/NUCLEO_F756ZG/webrepl_setup.py | 105 ++ .../stm32/NUCLEO_F756ZG/webrepl_setup.pyi | 10 + .../stm32/NUCLEO_F767ZI/dht.py | 47 + .../stm32/NUCLEO_F767ZI/dht.pyi | 15 + .../stm32/NUCLEO_F767ZI/mip/__init__.py | 187 ++ .../stm32/NUCLEO_F767ZI/mip/__init__.pyi | 15 + .../stm32/NUCLEO_F767ZI/modules.json | 56 + .../stm32/NUCLEO_F767ZI/ntptime.py | 68 + .../stm32/NUCLEO_F767ZI/ntptime.pyi | 5 + .../stm32/NUCLEO_F767ZI/onewire.py | 92 + .../stm32/NUCLEO_F767ZI/onewire.pyi | 21 + .../stm32/NUCLEO_F767ZI/removed.txt | 2 + .../stm32/NUCLEO_F767ZI/requests/__init__.py | 221 +++ .../stm32/NUCLEO_F767ZI/requests/__init__.pyi | 21 + .../stm32/NUCLEO_F767ZI/ssl.py | 63 + .../stm32/NUCLEO_F767ZI/ssl.pyi | 180 ++ .../stm32/NUCLEO_F767ZI/urequests.py | 8 + .../stm32/NUCLEO_F767ZI/urequests.pyi | 1 + .../stm32/NUCLEO_F767ZI/webrepl.py | 178 ++ .../stm32/NUCLEO_F767ZI/webrepl.pyi | 16 + .../stm32/NUCLEO_F767ZI/webrepl_setup.py | 105 ++ .../stm32/NUCLEO_F767ZI/webrepl_setup.pyi | 10 + .../stm32/NUCLEO_H723ZG/dht.py | 47 + .../stm32/NUCLEO_H723ZG/dht.pyi | 15 + .../stm32/NUCLEO_H723ZG/mip/__init__.py | 187 ++ .../stm32/NUCLEO_H723ZG/mip/__init__.pyi | 15 + .../stm32/NUCLEO_H723ZG/modules.json | 56 + .../stm32/NUCLEO_H723ZG/ntptime.py | 68 + .../stm32/NUCLEO_H723ZG/ntptime.pyi | 5 + .../stm32/NUCLEO_H723ZG/onewire.py | 92 + .../stm32/NUCLEO_H723ZG/onewire.pyi | 21 + .../stm32/NUCLEO_H723ZG/removed.txt | 2 + .../stm32/NUCLEO_H723ZG/requests/__init__.py | 221 +++ .../stm32/NUCLEO_H723ZG/requests/__init__.pyi | 21 + .../stm32/NUCLEO_H723ZG/ssl.py | 63 + .../stm32/NUCLEO_H723ZG/ssl.pyi | 180 ++ .../stm32/NUCLEO_H723ZG/urequests.py | 8 + .../stm32/NUCLEO_H723ZG/urequests.pyi | 1 + .../stm32/NUCLEO_H723ZG/webrepl.py | 178 ++ .../stm32/NUCLEO_H723ZG/webrepl.pyi | 16 + .../stm32/NUCLEO_H723ZG/webrepl_setup.py | 105 ++ .../stm32/NUCLEO_H723ZG/webrepl_setup.pyi | 10 + .../stm32/NUCLEO_H743ZI/dht.py | 47 + .../stm32/NUCLEO_H743ZI/dht.pyi | 15 + .../stm32/NUCLEO_H743ZI/mip/__init__.py | 187 ++ .../stm32/NUCLEO_H743ZI/mip/__init__.pyi | 15 + .../stm32/NUCLEO_H743ZI/modules.json | 56 + .../stm32/NUCLEO_H743ZI/ntptime.py | 68 + .../stm32/NUCLEO_H743ZI/ntptime.pyi | 5 + .../stm32/NUCLEO_H743ZI/onewire.py | 92 + .../stm32/NUCLEO_H743ZI/onewire.pyi | 21 + .../stm32/NUCLEO_H743ZI/removed.txt | 2 + .../stm32/NUCLEO_H743ZI/requests/__init__.py | 221 +++ .../stm32/NUCLEO_H743ZI/requests/__init__.pyi | 21 + .../stm32/NUCLEO_H743ZI/ssl.py | 63 + .../stm32/NUCLEO_H743ZI/ssl.pyi | 180 ++ .../stm32/NUCLEO_H743ZI/urequests.py | 8 + .../stm32/NUCLEO_H743ZI/urequests.pyi | 1 + .../stm32/NUCLEO_H743ZI/webrepl.py | 178 ++ .../stm32/NUCLEO_H743ZI/webrepl.pyi | 16 + .../stm32/NUCLEO_H743ZI/webrepl_setup.py | 105 ++ .../stm32/NUCLEO_H743ZI/webrepl_setup.pyi | 10 + .../stm32/NUCLEO_WL55/lora/__init__.py | 40 + .../stm32/NUCLEO_WL55/lora/__init__.pyi | 6 + .../stm32/NUCLEO_WL55/lora/modem.py | 463 +++++ .../stm32/NUCLEO_WL55/lora/modem.pyi | 54 + .../stm32/NUCLEO_WL55/lora/stm32wl5.py | 136 ++ .../stm32/NUCLEO_WL55/lora/stm32wl5.pyi | 30 + .../stm32/NUCLEO_WL55/lora/sx126x.py | 890 ++++++++++ .../stm32/NUCLEO_WL55/lora/sx126x.pyi | 160 ++ .../stm32/NUCLEO_WL55/lora/sync_modem.py | 86 + .../stm32/NUCLEO_WL55/lora/sync_modem.pyi | 5 + .../stm32/NUCLEO_WL55/modules.json | 40 + .../stm32/OLIMEX_E407/dht.py | 47 + .../stm32/OLIMEX_E407/dht.pyi | 15 + .../stm32/OLIMEX_E407/mip/__init__.py | 187 ++ .../stm32/OLIMEX_E407/mip/__init__.pyi | 15 + .../stm32/OLIMEX_E407/modules.json | 56 + .../stm32/OLIMEX_E407/ntptime.py | 68 + .../stm32/OLIMEX_E407/ntptime.pyi | 5 + .../stm32/OLIMEX_E407/onewire.py | 92 + .../stm32/OLIMEX_E407/onewire.pyi | 21 + .../stm32/OLIMEX_E407/removed.txt | 2 + .../stm32/OLIMEX_E407/requests/__init__.py | 221 +++ .../stm32/OLIMEX_E407/requests/__init__.pyi | 21 + .../stm32/OLIMEX_E407/ssl.py | 63 + .../stm32/OLIMEX_E407/ssl.pyi | 180 ++ .../stm32/OLIMEX_E407/urequests.py | 8 + .../stm32/OLIMEX_E407/urequests.pyi | 1 + .../stm32/OLIMEX_E407/webrepl.py | 178 ++ .../stm32/OLIMEX_E407/webrepl.pyi | 16 + .../stm32/OLIMEX_E407/webrepl_setup.py | 105 ++ .../stm32/OLIMEX_E407/webrepl_setup.pyi | 10 + .../stm32/OPENMV_N6/aioble/__init__.py | 32 + .../stm32/OPENMV_N6/aioble/__init__.pyi | 9 + .../stm32/OPENMV_N6/aioble/central.py | 305 ++++ .../stm32/OPENMV_N6/aioble/central.pyi | 70 + .../stm32/OPENMV_N6/aioble/client.py | 444 +++++ .../stm32/OPENMV_N6/aioble/client.pyi | 101 ++ .../stm32/OPENMV_N6/aioble/core.py | 78 + .../stm32/OPENMV_N6/aioble/core.pyi | 23 + .../stm32/OPENMV_N6/aioble/device.py | 304 ++++ .../stm32/OPENMV_N6/aioble/device.pyi | 66 + .../stm32/OPENMV_N6/aioble/l2cap.py | 214 +++ .../stm32/OPENMV_N6/aioble/l2cap.pyi | 40 + .../stm32/OPENMV_N6/aioble/peripheral.py | 176 ++ .../stm32/OPENMV_N6/aioble/peripheral.pyi | 44 + .../stm32/OPENMV_N6/aioble/security.py | 175 ++ .../stm32/OPENMV_N6/aioble/security.pyi | 27 + .../stm32/OPENMV_N6/aioble/server.py | 336 ++++ .../stm32/OPENMV_N6/aioble/server.pyi | 101 ++ .../stm32/OPENMV_N6/dht.py | 47 + .../stm32/OPENMV_N6/dht.pyi | 15 + .../stm32/OPENMV_N6/mip/__init__.py | 187 ++ .../stm32/OPENMV_N6/mip/__init__.pyi | 15 + .../stm32/OPENMV_N6/modules.json | 92 + .../stm32/OPENMV_N6/ntptime.py | 68 + .../stm32/OPENMV_N6/ntptime.pyi | 5 + .../stm32/OPENMV_N6/onewire.py | 92 + .../stm32/OPENMV_N6/onewire.pyi | 21 + .../stm32/OPENMV_N6/removed.txt | 2 + .../stm32/OPENMV_N6/requests/__init__.py | 221 +++ .../stm32/OPENMV_N6/requests/__init__.pyi | 21 + .../stm32/OPENMV_N6/ssl.py | 63 + .../stm32/OPENMV_N6/ssl.pyi | 180 ++ .../stm32/OPENMV_N6/urequests.py | 8 + .../stm32/OPENMV_N6/urequests.pyi | 1 + .../stm32/OPENMV_N6/webrepl.py | 178 ++ .../stm32/OPENMV_N6/webrepl.pyi | 16 + .../stm32/OPENMV_N6/webrepl_setup.py | 105 ++ .../stm32/OPENMV_N6/webrepl_setup.pyi | 10 + .../stm32/PYBD_SF2/dht.py | 47 + .../stm32/PYBD_SF2/dht.pyi | 15 + .../stm32/PYBD_SF2/lcd160cr.py | 479 ++++++ .../stm32/PYBD_SF2/lcd160cr.pyi | 507 ++++++ .../stm32/PYBD_SF2/mip/__init__.py | 187 ++ .../stm32/PYBD_SF2/mip/__init__.pyi | 15 + .../stm32/PYBD_SF2/modules.json | 60 + .../stm32/PYBD_SF2/ntptime.py | 68 + .../stm32/PYBD_SF2/ntptime.pyi | 5 + .../stm32/PYBD_SF2/onewire.py | 92 + .../stm32/PYBD_SF2/onewire.pyi | 21 + .../stm32/PYBD_SF2/removed.txt | 2 + .../stm32/PYBD_SF2/requests/__init__.py | 221 +++ .../stm32/PYBD_SF2/requests/__init__.pyi | 21 + .../stm32/PYBD_SF2/ssl.py | 63 + .../stm32/PYBD_SF2/ssl.pyi | 180 ++ .../stm32/PYBD_SF2/urequests.py | 8 + .../stm32/PYBD_SF2/urequests.pyi | 1 + .../stm32/PYBD_SF2/webrepl.py | 178 ++ .../stm32/PYBD_SF2/webrepl.pyi | 16 + .../stm32/PYBD_SF2/webrepl_setup.py | 105 ++ .../stm32/PYBD_SF2/webrepl_setup.pyi | 10 + .../stm32/PYBV10/dht.py | 47 + .../stm32/PYBV10/dht.pyi | 15 + .../stm32/PYBV10/lcd160cr.py | 479 ++++++ .../stm32/PYBV10/lcd160cr.pyi | 507 ++++++ .../stm32/PYBV10/modules.json | 32 + .../stm32/PYBV10/onewire.py | 92 + .../stm32/PYBV10/onewire.pyi | 21 + .../stm32/PYBV10/removed.txt | 2 + .../stm32/STM32F769DISC/dht.py | 47 + .../stm32/STM32F769DISC/dht.pyi | 15 + .../stm32/STM32F769DISC/mip/__init__.py | 187 ++ .../stm32/STM32F769DISC/mip/__init__.pyi | 15 + .../stm32/STM32F769DISC/modules.json | 56 + .../stm32/STM32F769DISC/ntptime.py | 68 + .../stm32/STM32F769DISC/ntptime.pyi | 5 + .../stm32/STM32F769DISC/onewire.py | 92 + .../stm32/STM32F769DISC/onewire.pyi | 21 + .../stm32/STM32F769DISC/removed.txt | 2 + .../stm32/STM32F769DISC/requests/__init__.py | 221 +++ .../stm32/STM32F769DISC/requests/__init__.pyi | 21 + .../stm32/STM32F769DISC/ssl.py | 63 + .../stm32/STM32F769DISC/ssl.pyi | 180 ++ .../stm32/STM32F769DISC/urequests.py | 8 + .../stm32/STM32F769DISC/urequests.pyi | 1 + .../stm32/STM32F769DISC/webrepl.py | 178 ++ .../stm32/STM32F769DISC/webrepl.pyi | 16 + .../stm32/STM32F769DISC/webrepl_setup.py | 105 ++ .../stm32/STM32F769DISC/webrepl_setup.pyi | 10 + .../stm32/STM32F7DISC/dht.py | 47 + .../stm32/STM32F7DISC/dht.pyi | 15 + .../stm32/STM32F7DISC/mip/__init__.py | 187 ++ .../stm32/STM32F7DISC/mip/__init__.pyi | 15 + .../stm32/STM32F7DISC/modules.json | 56 + .../stm32/STM32F7DISC/ntptime.py | 68 + .../stm32/STM32F7DISC/ntptime.pyi | 5 + .../stm32/STM32F7DISC/onewire.py | 92 + .../stm32/STM32F7DISC/onewire.pyi | 21 + .../stm32/STM32F7DISC/removed.txt | 2 + .../stm32/STM32F7DISC/requests/__init__.py | 221 +++ .../stm32/STM32F7DISC/requests/__init__.pyi | 21 + .../stm32/STM32F7DISC/ssl.py | 63 + .../stm32/STM32F7DISC/ssl.pyi | 180 ++ .../stm32/STM32F7DISC/urequests.py | 8 + .../stm32/STM32F7DISC/urequests.pyi | 1 + .../stm32/STM32F7DISC/webrepl.py | 178 ++ .../stm32/STM32F7DISC/webrepl.pyi | 16 + .../stm32/STM32F7DISC/webrepl_setup.py | 105 ++ .../stm32/STM32F7DISC/webrepl_setup.pyi | 10 + .../stm32/STM32H573I_DK/dht.py | 47 + .../stm32/STM32H573I_DK/dht.pyi | 15 + .../stm32/STM32H573I_DK/mip/__init__.py | 187 ++ .../stm32/STM32H573I_DK/mip/__init__.pyi | 15 + .../stm32/STM32H573I_DK/modules.json | 56 + .../stm32/STM32H573I_DK/ntptime.py | 68 + .../stm32/STM32H573I_DK/ntptime.pyi | 5 + .../stm32/STM32H573I_DK/onewire.py | 92 + .../stm32/STM32H573I_DK/onewire.pyi | 21 + .../stm32/STM32H573I_DK/removed.txt | 2 + .../stm32/STM32H573I_DK/requests/__init__.py | 221 +++ .../stm32/STM32H573I_DK/requests/__init__.pyi | 21 + .../stm32/STM32H573I_DK/ssl.py | 63 + .../stm32/STM32H573I_DK/ssl.pyi | 180 ++ .../stm32/STM32H573I_DK/urequests.py | 8 + .../stm32/STM32H573I_DK/urequests.pyi | 1 + .../stm32/STM32H573I_DK/webrepl.py | 178 ++ .../stm32/STM32H573I_DK/webrepl.pyi | 16 + .../stm32/STM32H573I_DK/webrepl_setup.py | 105 ++ .../stm32/STM32H573I_DK/webrepl_setup.pyi | 10 + .../stm32/VCC_GND_F407ZG/dht.py | 47 + .../stm32/VCC_GND_F407ZG/dht.pyi | 15 + .../stm32/VCC_GND_F407ZG/mip/__init__.py | 187 ++ .../stm32/VCC_GND_F407ZG/mip/__init__.pyi | 15 + .../stm32/VCC_GND_F407ZG/modules.json | 56 + .../stm32/VCC_GND_F407ZG/ntptime.py | 68 + .../stm32/VCC_GND_F407ZG/ntptime.pyi | 5 + .../stm32/VCC_GND_F407ZG/onewire.py | 92 + .../stm32/VCC_GND_F407ZG/onewire.pyi | 21 + .../stm32/VCC_GND_F407ZG/removed.txt | 2 + .../stm32/VCC_GND_F407ZG/requests/__init__.py | 221 +++ .../VCC_GND_F407ZG/requests/__init__.pyi | 21 + .../stm32/VCC_GND_F407ZG/ssl.py | 63 + .../stm32/VCC_GND_F407ZG/ssl.pyi | 180 ++ .../stm32/VCC_GND_F407ZG/urequests.py | 8 + .../stm32/VCC_GND_F407ZG/urequests.pyi | 1 + .../stm32/VCC_GND_F407ZG/webrepl.py | 178 ++ .../stm32/VCC_GND_F407ZG/webrepl.pyi | 16 + .../stm32/VCC_GND_F407ZG/webrepl_setup.py | 105 ++ .../stm32/VCC_GND_F407ZG/webrepl_setup.pyi | 10 + .../unix/GENERIC/argparse.py | 226 +++ .../unix/GENERIC/argparse.pyi | 28 + .../unix/GENERIC/mip/__init__.py | 187 ++ .../unix/GENERIC/mip/__init__.pyi | 15 + .../unix/GENERIC/mip/__main__.py | 46 + .../unix/GENERIC/mip/__main__.pyi | 1 + .../unix/GENERIC/modules.json | 40 + .../unix/GENERIC/removed.txt | 2 + .../unix/GENERIC/requests/__init__.py | 221 +++ .../unix/GENERIC/requests/__init__.pyi | 21 + .../unix/GENERIC/ssl.py | 63 + .../unix/GENERIC/ssl.pyi | 180 ++ .../webassembly/GENERIC/abc.py | 6 + .../webassembly/GENERIC/abc.pyi | 3 + .../webassembly/GENERIC/base64.py | 480 ++++++ .../webassembly/GENERIC/base64.pyi | 133 ++ .../webassembly/GENERIC/binascii.py | 362 ++++ .../webassembly/GENERIC/binascii.pyi | 44 + .../GENERIC/collections/__init__.py | 12 + .../GENERIC/collections/__init__.pyi | 21 + .../GENERIC/collections/defaultdict.py | 35 + .../GENERIC/collections/defaultdict.pyi | 13 + .../webassembly/GENERIC/copy.py | 380 ++++ .../webassembly/GENERIC/copy.pyi | 19 + .../webassembly/GENERIC/datetime.py | 861 ++++++++++ .../webassembly/GENERIC/datetime.pyi | 229 +++ .../webassembly/GENERIC/fnmatch.py | 140 ++ .../webassembly/GENERIC/fnmatch.pyi | 33 + .../webassembly/GENERIC/functools.py | 28 + .../webassembly/GENERIC/functools.pyi | 4 + .../webassembly/GENERIC/gzip.py | 29 + .../webassembly/GENERIC/gzip.pyi | 77 + .../webassembly/GENERIC/hmac.py | 87 + .../webassembly/GENERIC/hmac.pyi | 17 + .../webassembly/GENERIC/html/__init__.py | 29 + .../webassembly/GENERIC/html/__init__.pyi | 12 + .../webassembly/GENERIC/inspect.py | 82 + .../webassembly/GENERIC/inspect.pyi | 28 + .../webassembly/GENERIC/io.py | 5 + .../webassembly/GENERIC/io.pyi | 217 +++ .../webassembly/GENERIC/itertools.py | 74 + .../webassembly/GENERIC/itertools.pyi | 11 + .../webassembly/GENERIC/locale.py | 2 + .../webassembly/GENERIC/locale.pyi | 1 + .../webassembly/GENERIC/logging.py | 253 +++ .../webassembly/GENERIC/logging.pyi | 86 + .../webassembly/GENERIC/modules.json | 140 ++ .../webassembly/GENERIC/operator.py | 43 + .../webassembly/GENERIC/operator.pyi | 10 + .../webassembly/GENERIC/os/__init__.py | 8 + .../webassembly/GENERIC/os/__init__.pyi | 211 +++ .../webassembly/GENERIC/os/path.py | 83 + .../webassembly/GENERIC/os/path.pyi | 16 + .../webassembly/GENERIC/pathlib.py | 210 +++ .../webassembly/GENERIC/pathlib.pyi | 50 + .../webassembly/GENERIC/removed.txt | 2 + .../webassembly/GENERIC/stat.py | 154 ++ .../webassembly/GENERIC/stat.pyi | 87 + .../webassembly/GENERIC/string.py | 27 + .../webassembly/GENERIC/string.pyi | 13 + .../webassembly/GENERIC/tarfile/__init__.py | 148 ++ .../webassembly/GENERIC/tarfile/__init__.pyi | 46 + .../webassembly/GENERIC/tarfile/write.py | 121 ++ .../webassembly/GENERIC/tarfile/write.pyi | 11 + .../webassembly/GENERIC/time.py | 79 + .../webassembly/GENERIC/time.pyi | 59 + .../webassembly/GENERIC/types.py | 120 ++ .../webassembly/GENERIC/types.pyi | 45 + .../webassembly/GENERIC/unittest/__init__.py | 463 +++++ .../webassembly/GENERIC/unittest/__init__.pyi | 88 + .../webassembly/GENERIC/uu.py | 218 +++ .../webassembly/GENERIC/uu.pyi | 9 + .../webassembly/GENERIC/zlib.py | 39 + .../webassembly/GENERIC/zlib.pyi | 90 + .../windows/GENERIC/modules.json | 24 + .../windows/GENERIC/removed.txt | 2 + .../windows/GENERIC/ssl.py | 63 + .../windows/GENERIC/ssl.pyi | 180 ++ .../zephyr/GENERIC/modules.json | 24 + .../zephyr/GENERIC/upysh.py | 124 ++ .../zephyr/GENERIC/upysh.pyi | 32 + 2500 files changed, 217725 insertions(+) create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_decoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_decoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_encoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_encoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/logging.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/logging.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_base.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_base.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_pack.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_pack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_record.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_record.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_unit.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_unit.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/time.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/time.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lilygo_oled.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lilygo_oled.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lora32.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lora32.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssd1306.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssd1306.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/c3mini.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/c3mini.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/s2mini.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/s2mini.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico_oled.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico_oled.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssd1306.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssd1306.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/atom.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/atom.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/sdcard.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/sdcard.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dotstar.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dotstar.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/feathers2.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/feathers2.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/feathers2neo.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/feathers2neo.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/feathers3.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/feathers3.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/feathers3neo.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/feathers3neo.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/nanos3.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/nanos3.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/max17048.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/max17048.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/omgs3.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/omgs3.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/pros3.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/pros3.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dotstar.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dotstar.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/tinypico.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/tinypico.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/tinys2.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/tinys2.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/aioespnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/aioespnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/apa106.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/apa106.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/machine.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/machine.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/tinys3.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/tinys3.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/robust.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/robust.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/simple.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/simple.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/upysh.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/apa102.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/apa102.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/espnow.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/espnow.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/flashbdev.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/flashbdev.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/inisetup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/inisetup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/port_diag.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/port_diag.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.py create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.py create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.py create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.py create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.py create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/imu.py create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/imu.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.py create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lsm9ds1.py create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lsm9ds1.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/GENERIC/_mkfs.py create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/GENERIC/_mkfs.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/nrf/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_decoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_decoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_encoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_encoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/logging.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/logging.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_base.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_base.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_pack.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_pack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_record.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_record.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_unit.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_unit.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/time.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/time.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/sdcard.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/sdcard.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/sdcard.py create mode 100644 stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/sdcard.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_decoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_decoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_encoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_encoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/espflash.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/espflash.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/logging.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/logging.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_base.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_base.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_pack.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_pack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_record.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_record.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_unit.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_unit.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/time.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/time.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/board.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/board.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/sdcard.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/sdcard.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/sdcard.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/sdcard.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/board.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/board.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot_fat.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot_fat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/_boot.py create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/_boot.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/ds18x20.py create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/ds18x20.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/samd/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_decoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_decoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_encoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_encoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/logging.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/logging.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpack.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpackrpc.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpackrpc.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_base.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_base.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_pack.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_pack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_record.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_record.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_unit.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_unit.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/time.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/time.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_decoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_decoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_encoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_encoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/logging.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/logging.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpack.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpackrpc.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpackrpc.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/iso7816.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/iso7816.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/se05x.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/se05x.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_base.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_base.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_pack.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_pack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_record.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_record.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_unit.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_unit.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/time.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/time.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_decoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_decoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_encoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_encoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/logging.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/logging.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpack.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpackrpc.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpackrpc.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/opta.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/opta.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_base.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_base.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_pack.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_pack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_record.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_record.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_unit.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_unit.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/time.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/time.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_decoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_decoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_encoder.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_encoder.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cmwx1.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cmwx1.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/logging.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/logging.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpack.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpackrpc.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpackrpc.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/iso7816.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/iso7816.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/se05x.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/se05x.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_base.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_base.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_pack.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_pack.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_record.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_record.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_unit.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_unit.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/time.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/time.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/ssd1306.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/ssd1306.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/GENERIC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/GENERIC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/GENERIC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/GENERIC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/appupdate.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/appupdate.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/fwupdate.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/fwupdate.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/appupdate.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/appupdate.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/fwupdate.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/fwupdate.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/modem.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/modem.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/stm32wl5.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/stm32wl5.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sx126x.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sx126x.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sync_modem.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sync_modem.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/central.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/central.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/client.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/client.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/core.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/core.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/device.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/device.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/l2cap.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/l2cap.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/peripheral.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/peripheral.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/security.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/security.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/server.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/server.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/lcd160cr.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/lcd160cr.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBV10/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBV10/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBV10/lcd160cr.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBV10/lcd160cr.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBV10/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBV10/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBV10/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/PYBV10/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/dht.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/dht.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ntptime.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ntptime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/onewire.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/onewire.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/urequests.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/urequests.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl_setup.py create mode 100644 stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl_setup.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/argparse.py create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/argparse.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__main__.py create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__main__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/requests/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/requests/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/unix/GENERIC/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/abc.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/abc.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/base64.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/base64.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/binascii.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/binascii.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/defaultdict.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/defaultdict.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/copy.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/copy.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/datetime.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/datetime.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/fnmatch.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/fnmatch.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/functools.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/functools.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/gzip.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/gzip.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/hmac.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/hmac.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/html/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/html/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/inspect.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/inspect.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/io.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/io.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/itertools.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/itertools.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/locale.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/locale.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/logging.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/logging.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/operator.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/operator.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/path.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/path.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/pathlib.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/pathlib.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/stat.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/stat.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/string.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/string.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/write.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/write.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/time.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/time.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/types.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/types.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/unittest/__init__.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/unittest/__init__.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/uu.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/uu.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/zlib.py create mode 100644 stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/zlib.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/windows/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/windows/GENERIC/removed.txt create mode 100644 stubs/micropython-v1_26_1-frozen/windows/GENERIC/ssl.py create mode 100644 stubs/micropython-v1_26_1-frozen/windows/GENERIC/ssl.pyi create mode 100644 stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/modules.json create mode 100644 stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/upysh.py create mode 100644 stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/upysh.pyi diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/_boot.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/_boot.py new file mode 100644 index 000000000..36044b461 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/_boot.py @@ -0,0 +1,23 @@ +import sys, os, alif + + +bdev = alif.Flash() +if hasattr(alif, "usb_msc"): + try: + # This may fail on VfsFat construction, or mount. + os.mount(os.VfsFat(bdev), "/flash") + except: + os.VfsFat.mkfs(bdev) + os.mount(os.VfsFat(bdev), "/flash") +else: + try: + os.mount(os.VfsLfs2(bdev, progsize=256), "/flash") + except: + os.VfsLfs2.mkfs(bdev, progsize=256) + os.mount(os.VfsLfs2(bdev, progsize=256), "/flash") + +sys.path.append("/flash") +sys.path.append("/flash/lib") +os.chdir("/flash") + +del sys, os, alif, bdev diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/_boot.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/_boot.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/_boot.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/dht.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/dht.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/modules.json new file mode 100644 index 000000000..fbd3a27b3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/modules.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "alif", + "platform": "alif", + "machine": "GENERIC", + "firmware": "micropython-alif-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/neopixel.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ntptime.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/onewire.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ssl.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ssl.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/urequests.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/urequests.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/alif/GENERIC/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/central.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/client.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/core.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/device.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/security.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/server.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/__init__.py new file mode 100644 index 000000000..80790f0da --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/__init__.py @@ -0,0 +1,32 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from ._decoder import CBORDecoder +from ._decoder import load +from ._decoder import loads + +from ._encoder import CBOREncoder +from ._encoder import dump +from ._encoder import dumps diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/__init__.pyi new file mode 100644 index 000000000..0ef59d019 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/__init__.pyi @@ -0,0 +1,2 @@ +from ._decoder import CBORDecoder as CBORDecoder, load as load, loads as loads +from ._encoder import CBOREncoder as CBOREncoder, dump as dump, dumps as dumps diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_decoder.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_decoder.py new file mode 100644 index 000000000..8434aec26 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_decoder.py @@ -0,0 +1,254 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + + +break_marker = object() + + +class CBORSimpleValue(object): + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + def __init__(self, value): + if value < 0 or value > 255: + raise TypeError("simple value too big") + self.value = value + + def __eq__(self, other): + if isinstance(other, CBORSimpleValue): + return self.value == other.value + elif isinstance(other, int): + return self.value == other + return NotImplemented + + def __repr__(self): + return "CBORSimpleValue({self.value})".format(self=self) + + +def decode_uint(decoder, subtype, allow_indefinite=False): + # Major tag 0 + if subtype < 24: + return subtype + elif subtype == 24: + return struct.unpack(">B", decoder.read(1))[0] + elif subtype == 25: + return struct.unpack(">H", decoder.read(2))[0] + elif subtype == 26: + return struct.unpack(">L", decoder.read(4))[0] + elif subtype == 27: + return struct.unpack(">Q", decoder.read(8))[0] + elif subtype == 31 and allow_indefinite: + return None + else: + raise CBORDecodeError("unknown unsigned integer subtype 0x%x" % subtype) + + +def decode_negint(decoder, subtype): + # Major tag 1 + uint = decode_uint(decoder, subtype) + return -uint - 1 + + +def decode_bytestring(decoder, subtype): + # Major tag 2 + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + buf = bytearray() + while True: + initial_byte = decoder.read(1)[0] + if initial_byte == 255: + return buf + else: + length = decode_uint(decoder, initial_byte & 31) + value = decoder.read(length) + buf.extend(value) + else: + return decoder.read(length) + + +def decode_string(decoder, subtype): + # Major tag 3 + return decode_bytestring(decoder, subtype).decode("utf-8") + + +def decode_array(decoder, subtype): + # Major tag 4 + items = [] + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + value = decoder.decode() + if value is break_marker: + break + else: + items.append(value) + else: + for _ in range(length): + item = decoder.decode() + items.append(item) + return items + + +def decode_map(decoder, subtype): + # Major tag 5 + dictionary = {} + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + key = decoder.decode() + if key is break_marker: + break + else: + value = decoder.decode() + dictionary[key] = value + else: + for _ in range(length): + key = decoder.decode() + value = decoder.decode() + dictionary[key] = value + + return dictionary + + +def decode_special(decoder, subtype): + # Simple value + if subtype < 20: + return CBORSimpleValue(subtype) + + # Major tag 7 + return special_decoders[subtype](decoder) + + +def decode_simple_value(decoder): + return CBORSimpleValue(struct.unpack(">B", decoder.read(1))[0]) + + +def decode_float16(decoder): + decoder.read(2) + raise NotImplementedError # no float16 unpack function + + +def decode_float32(decoder): + return struct.unpack(">f", decoder.read(4))[0] + + +def decode_float64(decoder): + return struct.unpack(">d", decoder.read(8))[0] + + +major_decoders = { + 0: decode_uint, + 1: decode_negint, + 2: decode_bytestring, + 3: decode_string, + 4: decode_array, + 5: decode_map, + 7: decode_special, +} + +special_decoders = { + 20: lambda self: False, + 21: lambda self: True, + 22: lambda self: None, + # 23 is undefined + 24: decode_simple_value, + 25: decode_float16, + 26: decode_float32, + 27: decode_float64, + 31: lambda self: break_marker, +} + + +class CBORDecoder(object): + """ + Deserializes a CBOR encoded byte stream. + """ + + def __init__(self, fp): + self.fp = fp + + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + data = self.fp.read(amount) + if len(data) < amount: + raise CBORDecodeError("premature end of stream (expected to read {} bytes, got {} instead)".format(amount, len(data))) + + return data + + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + try: + initial_byte = self.fp.read(1)[0] + major_type = initial_byte >> 5 + subtype = initial_byte & 31 + except Exception as e: + raise CBORDecodeError("error reading major type at index {}: {}".format(self.fp.tell(), e)) + + decoder = major_decoders[major_type] + try: + return decoder(self, subtype) + except CBORDecodeError: + raise + except Exception as e: + raise CBORDecodeError("error decoding value {}".format(e)) # tell doesn't work on micropython at the moment + + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + fp = io.BytesIO(payload) + return CBORDecoder(fp, **kwargs).decode() + + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + return CBORDecoder(fp, **kwargs).decode() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_decoder.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_decoder.pyi new file mode 100644 index 000000000..d4daffe85 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_decoder.pyi @@ -0,0 +1,66 @@ +from _typeshed import Incomplete + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + +break_marker: Incomplete + +class CBORSimpleValue: + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + value: Incomplete + def __init__(self, value) -> None: ... + def __eq__(self, other): ... + def __repr__(self) -> str: ... + +def decode_uint(decoder, subtype, allow_indefinite: bool = False): ... +def decode_negint(decoder, subtype): ... +def decode_bytestring(decoder, subtype): ... +def decode_string(decoder, subtype): ... +def decode_array(decoder, subtype): ... +def decode_map(decoder, subtype): ... +def decode_special(decoder, subtype): ... +def decode_simple_value(decoder): ... +def decode_float16(decoder) -> None: ... +def decode_float32(decoder): ... +def decode_float64(decoder): ... + +major_decoders: Incomplete +special_decoders: Incomplete + +class CBORDecoder: + """ + Deserializes a CBOR encoded byte stream. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_encoder.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_encoder.py new file mode 100644 index 000000000..fe8715468 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_encoder.py @@ -0,0 +1,182 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + + +def encode_length(major_tag, length): + if length < 24: + return struct.pack(">B", major_tag | length) + elif length < 256: + return struct.pack(">BB", major_tag | 24, length) + elif length < 65536: + return struct.pack(">BH", major_tag | 25, length) + elif length < 4294967296: + return struct.pack(">BL", major_tag | 26, length) + else: + return struct.pack(">BQ", major_tag | 27, length) + + +def encode_semantic(encoder, tag, value): + encoder.write(encode_length(0xC0, tag)) + encoder.encode(value) + + +def encode_float(encoder, value): + # Handle special values efficiently + import math + + if math.isnan(value): + encoder.write(b"\xf9\x7e\x00") + elif math.isinf(value): + encoder.write(b"\xf9\x7c\x00" if value > 0 else b"\xf9\xfc\x00") + else: + encoder.write(struct.pack(">Bd", 0xFB, value)) + + +def encode_int(encoder, value): + # Big integers (2 ** 64 and over) + if value >= 18446744073709551616 or value < -18446744073709551616: + if value >= 0: + major_type = 0x02 + else: + major_type = 0x03 + value = -value - 1 + + values = [] + while value > 0: + value, remainder = divmod(value, 256) + values.insert(0, remainder) + + payload = bytes(values) + encode_semantic(encoder, major_type, payload) + elif value >= 0: + encoder.write(encode_length(0, value)) + else: + encoder.write(encode_length(0x20, abs(value) - 1)) + + +def encode_bytestring(encoder, value): + encoder.write(encode_length(0x40, len(value)) + value) + + +def encode_bytearray(encoder, value): + encode_bytestring(encoder, bytes(value)) + + +def encode_string(encoder, value): + encoded = value.encode("utf-8") + encoder.write(encode_length(0x60, len(encoded)) + encoded) + + +def encode_map(encoder, value): + encoder.write(encode_length(0xA0, len(value))) + for key, val in value.items(): + encoder.encode(key) + encoder.encode(val) + + +def encode_array(encoder, value): + encoder.write(encode_length(0x80, len(value))) + for item in value: + encoder.encode(item) + + +def encode_boolean(encoder, value): + encoder.write(b"\xf5" if value else b"\xf4") + + +def encode_none(encoder, value): + encoder.write(b"\xf6") + + +cbor_encoders = { # supported data types and the encoder to use. + bytes: encode_bytestring, + bytearray: encode_bytearray, + str: encode_string, + int: encode_int, + float: encode_float, + bool: encode_boolean, + type(None): encode_none, + list: encode_array, + dict: encode_map, +} + + +class CBOREncoder(object): + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + def __init__(self, fp): + self.fp = fp + + def _find_encoder(self, obj): + return cbor_encoders[type(obj)] + + def write(self, data): + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + self.fp.write(data) + + def encode(self, obj): + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + encoder = self._find_encoder(obj) + if not encoder: + raise CBOREncodeError("cannot serialize type %s" % type(obj)) + encoder(self, obj) + + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + fp = io.BytesIO() + dump(obj, fp, **kwargs) + return fp.getvalue() + + +def dump(obj, fp, **kwargs): + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ + CBOREncoder(fp, **kwargs).encode(obj) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_encoder.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_encoder.pyi new file mode 100644 index 000000000..8cd761686 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/cbor2/_encoder.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + +def encode_length(major_tag, length): ... +def encode_semantic(encoder, tag, value) -> None: ... +def encode_float(encoder, value) -> None: ... +def encode_int(encoder, value) -> None: ... +def encode_bytestring(encoder, value) -> None: ... +def encode_bytearray(encoder, value) -> None: ... +def encode_string(encoder, value) -> None: ... +def encode_map(encoder, value) -> None: ... +def encode_array(encoder, value) -> None: ... +def encode_boolean(encoder, value) -> None: ... +def encode_none(encoder, value) -> None: ... + +cbor_encoders: Incomplete + +class CBOREncoder: + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def _find_encoder(self, obj): ... + def write(self, data) -> None: + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + def encode(self, obj) -> None: + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + +def dump(obj, fp, **kwargs) -> None: + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/logging.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/logging.py new file mode 100644 index 000000000..edee407c6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/logging.py @@ -0,0 +1,253 @@ +from micropython import const +import io +import sys +import time + +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 + +_DEFAULT_LEVEL = WARNING + +_level_dict = { + CRITICAL: "CRITICAL", + ERROR: "ERROR", + WARNING: "WARNING", + INFO: "INFO", + DEBUG: "DEBUG", + NOTSET: "NOTSET", +} + +_loggers = {} +_stream = sys.stderr +_default_fmt = "%(levelname)s:%(name)s:%(message)s" +_default_datefmt = "%Y-%m-%d %H:%M:%S" + + +class LogRecord: + def set(self, name, level, message): + self.name = name + self.levelno = level + self.levelname = _level_dict[level] + self.message = message + self.ct = time.time() + self.msecs = int((self.ct - int(self.ct)) * 1000) + self.asctime = None + + +class Handler: + def __init__(self, level=NOTSET): + self.level = level + self.formatter = None + + def close(self): + pass + + def setLevel(self, level): + self.level = level + + def setFormatter(self, formatter): + self.formatter = formatter + + def format(self, record): + return self.formatter.format(record) + + +class StreamHandler(Handler): + def __init__(self, stream=None): + super().__init__() + self.stream = _stream if stream is None else stream + self.terminator = "\n" + + def close(self): + if hasattr(self.stream, "flush"): + self.stream.flush() + + def emit(self, record): + if record.levelno >= self.level: + self.stream.write(self.format(record) + self.terminator) + + +class FileHandler(StreamHandler): + def __init__(self, filename, mode="a", encoding="UTF-8"): + super().__init__(stream=open(filename, mode=mode, encoding=encoding)) + + def close(self): + super().close() + self.stream.close() + + +class Formatter: + def __init__(self, fmt=None, datefmt=None): + self.fmt = _default_fmt if fmt is None else fmt + self.datefmt = _default_datefmt if datefmt is None else datefmt + + def usesTime(self): + return "asctime" in self.fmt + + def formatTime(self, datefmt, record): + if hasattr(time, "strftime"): + return time.strftime(datefmt, time.localtime(record.ct)) + return None + + def format(self, record): + if self.usesTime(): + record.asctime = self.formatTime(self.datefmt, record) + return self.fmt % { + "name": record.name, + "message": record.message, + "msecs": record.msecs, + "asctime": record.asctime, + "levelname": record.levelname, + } + + +class Logger: + def __init__(self, name, level=NOTSET): + self.name = name + self.level = level + self.handlers = [] + self.record = LogRecord() + + def setLevel(self, level): + self.level = level + + def isEnabledFor(self, level): + return level >= self.getEffectiveLevel() + + def getEffectiveLevel(self): + return self.level or getLogger().level or _DEFAULT_LEVEL + + def log(self, level, msg, *args): + if self.isEnabledFor(level): + if args: + if isinstance(args[0], dict): + args = args[0] + msg = msg % args + self.record.set(self.name, level, msg) + handlers = self.handlers + if not handlers: + handlers = getLogger().handlers + for h in handlers: + h.emit(self.record) + + def debug(self, msg, *args): + self.log(DEBUG, msg, *args) + + def info(self, msg, *args): + self.log(INFO, msg, *args) + + def warning(self, msg, *args): + self.log(WARNING, msg, *args) + + def error(self, msg, *args): + self.log(ERROR, msg, *args) + + def critical(self, msg, *args): + self.log(CRITICAL, msg, *args) + + def exception(self, msg, *args, exc_info=True): + self.log(ERROR, msg, *args) + tb = None + if isinstance(exc_info, BaseException): + tb = exc_info + elif hasattr(sys, "exc_info"): + tb = sys.exc_info()[1] + if tb: + buf = io.StringIO() + sys.print_exception(tb, buf) + self.log(ERROR, buf.getvalue()) + + def addHandler(self, handler): + self.handlers.append(handler) + + def hasHandlers(self): + return len(self.handlers) > 0 + + +def getLogger(name=None): + if name is None: + name = "root" + if name not in _loggers: + _loggers[name] = Logger(name) + if name == "root": + basicConfig() + return _loggers[name] + + +def log(level, msg, *args): + getLogger().log(level, msg, *args) + + +def debug(msg, *args): + getLogger().debug(msg, *args) + + +def info(msg, *args): + getLogger().info(msg, *args) + + +def warning(msg, *args): + getLogger().warning(msg, *args) + + +def error(msg, *args): + getLogger().error(msg, *args) + + +def critical(msg, *args): + getLogger().critical(msg, *args) + + +def exception(msg, *args, exc_info=True): + getLogger().exception(msg, *args, exc_info=exc_info) + + +def shutdown(): + for k, logger in _loggers.items(): + for h in logger.handlers: + h.close() + _loggers.pop(logger, None) + + +def addLevelName(level, name): + _level_dict[level] = name + + +def basicConfig( + filename=None, + filemode="a", + format=None, + datefmt=None, + level=WARNING, + stream=None, + encoding="UTF-8", + force=False, +): + if "root" not in _loggers: + _loggers["root"] = Logger("root") + + logger = _loggers["root"] + + if force or not logger.handlers: + for h in logger.handlers: + h.close() + logger.handlers = [] + + if filename is None: + handler = StreamHandler(stream) + else: + handler = FileHandler(filename, filemode, encoding) + + handler.setLevel(level) + handler.setFormatter(Formatter(format, datefmt)) + + logger.setLevel(level) + logger.addHandler(handler) + + +if hasattr(sys, "atexit"): + sys.atexit(shutdown) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/logging.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/logging.pyi new file mode 100644 index 000000000..856bcccf7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/logging.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete +from micropython import const as const + +CRITICAL: int +ERROR: int +WARNING: int +INFO: int +DEBUG: int +NOTSET: int +_DEFAULT_LEVEL = WARNING +_level_dict: Incomplete +_loggers: Incomplete +_stream: Incomplete +_default_fmt: str +_default_datefmt: str + +class LogRecord: + name: Incomplete + levelno: Incomplete + levelname: Incomplete + message: Incomplete + ct: Incomplete + msecs: Incomplete + asctime: Incomplete + def set(self, name, level, message) -> None: ... + +class Handler: + level: Incomplete + formatter: Incomplete + def __init__(self, level=...) -> None: ... + def close(self) -> None: ... + def setLevel(self, level) -> None: ... + def setFormatter(self, formatter) -> None: ... + def format(self, record): ... + +class StreamHandler(Handler): + stream: Incomplete + terminator: str + def __init__(self, stream=None) -> None: ... + def close(self) -> None: ... + def emit(self, record) -> None: ... + +class FileHandler(StreamHandler): + def __init__(self, filename, mode: str = "a", encoding: str = "UTF-8") -> None: ... + def close(self) -> None: ... + +class Formatter: + fmt: Incomplete + datefmt: Incomplete + def __init__(self, fmt=None, datefmt=None) -> None: ... + def usesTime(self): ... + def formatTime(self, datefmt, record): ... + def format(self, record): ... + +class Logger: + name: Incomplete + level: Incomplete + handlers: Incomplete + record: Incomplete + def __init__(self, name, level=...) -> None: ... + def setLevel(self, level) -> None: ... + def isEnabledFor(self, level): ... + def getEffectiveLevel(self): ... + def log(self, level, msg, *args) -> None: ... + def debug(self, msg, *args) -> None: ... + def info(self, msg, *args) -> None: ... + def warning(self, msg, *args) -> None: ... + def error(self, msg, *args) -> None: ... + def critical(self, msg, *args) -> None: ... + def exception(self, msg, *args, exc_info: bool = True) -> None: ... + def addHandler(self, handler) -> None: ... + def hasHandlers(self): ... + +def getLogger(name=None): ... +def log(level, msg, *args) -> None: ... +def debug(msg, *args) -> None: ... +def info(msg, *args) -> None: ... +def warning(msg, *args) -> None: ... +def error(msg, *args) -> None: ... +def critical(msg, *args) -> None: ... +def exception(msg, *args, exc_info: bool = True) -> None: ... +def shutdown() -> None: ... +def addLevelName(level, name) -> None: ... +def basicConfig( + filename=None, filemode: str = "a", format=None, datefmt=None, level=..., stream=None, encoding: str = "UTF-8", force: bool = False +) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/modules.json new file mode 100644 index 000000000..8fc0c78f5 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/modules.json @@ -0,0 +1,184 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "ARDUINO_NANO_ESP32", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "cbor2/__init__.py", + "module": "__init__" + }, + { + "file": "cbor2/_decoder.py", + "module": "_decoder" + }, + { + "file": "cbor2/_encoder.py", + "module": "_encoder" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "logging.py", + "module": "logging" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "senml/__init__.py", + "module": "__init__" + }, + { + "file": "senml/senml_base.py", + "module": "senml_base" + }, + { + "file": "senml/senml_pack.py", + "module": "senml_pack" + }, + { + "file": "senml/senml_record.py", + "module": "senml_record" + }, + { + "file": "senml/senml_unit.py", + "module": "senml_unit" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "time.py", + "module": "time" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/__init__.py new file mode 100644 index 000000000..908375fdb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/__init__.py @@ -0,0 +1,29 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from .senml_base import SenmlBase +from .senml_pack import SenmlPack +from .senml_record import SenmlRecord +from .senml_unit import SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/__init__.pyi new file mode 100644 index 000000000..c72285dc4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/__init__.pyi @@ -0,0 +1,4 @@ +from .senml_base import SenmlBase as SenmlBase +from .senml_pack import SenmlPack as SenmlPack +from .senml_record import SenmlRecord as SenmlRecord +from .senml_unit import SenmlUnits as SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_base.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_base.py new file mode 100644 index 000000000..b277c9477 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_base.py @@ -0,0 +1,30 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +class SenmlBase(object): + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_base.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_base.pyi new file mode 100644 index 000000000..240f185ce --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_base.pyi @@ -0,0 +1,4 @@ +class SenmlBase: + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_pack.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_pack.py new file mode 100644 index 000000000..5a0554467 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_pack.py @@ -0,0 +1,358 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from senml.senml_record import SenmlRecord +from senml.senml_base import SenmlBase +import json +import cbor2 + + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + def __init__(self, list): + self._list = list + self._index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self._index < len(self._list): + res = self._list[self._index] + self._index += 1 + return res + else: + raise StopIteration + + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings = { + "bn": "bn", + "bt": "bt", + "bu": "bu", + "bv": "bv", + "bs": "bs", + "n": "n", + "u": "u", + "v": "v", + "vs": "vs", + "vb": "vb", + "vd": "vd", + "s": "s", + "t": "t", + "ut": "ut", + } + + def __init__(self, name, callback=None): + """ + initialize the object + :param name: {string} the name of the pack + """ + self._data = [] + self.name = name + self._base_value = None + self._base_time = None + self._base_sum = None + self.base_unit = None + self._parent = None # a pack can also be the child of another pack. + self.actuate = callback # actuate callback function + + def __iter__(self): + return SenmlPackIterator(self._data) + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + return self._base_value + + @base_value.setter + def base_value(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_value") + self._base_value = value + + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + return self._base_sum + + @base_sum.setter + def base_sum(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_sum") + self._base_sum = value + + @property + def base_time(self): + return self._base_time + + @base_time.setter + def base_time(self, value): + self._check_value_type(value, "base_time") + self._base_time = value + + def _check_value_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + def from_json(self, data): + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + records = json.loads(data) # load the raw senml data + self._process_incomming_data(records, SenmlPack.json_mappings) + + def _process_incomming_data(self, records, naming_map): + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + cur_pack_el = self + new_pack = False + for item in records: + if naming_map["bn"] in item: # ref to a pack element, either this or a child pack. + if item[naming_map["bn"]] != self.name: + pack_el = [x for x in self._data if x.name == item[naming_map["bn"]]] + else: + pack_el = [self] + if len(pack_el) > 0: + cur_pack_el = pack_el[0] + new_pack = False + else: + device = SenmlPack(item[naming_map["bn"]]) + self._data.append(device) + cur_pack_el = device + new_pack = True + + if ( + naming_map["bv"] in item + ): # need to copy the base value assigned to the pack element so we can do proper conversion for actuators. + cur_pack_el.base_value = item[naming_map["bv"]] + + rec_el = [x for x in cur_pack_el._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + else: + rec_el = [x for x in self._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + + def do_actuate(self, raw, naming_map, device=None): + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + rec = SenmlRecord(raw[naming_map["n"]]) + if device: + device.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=device) + else: + self.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=None) + + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + converted = [] + self._build_rec_dict(SenmlPack.json_mappings, converted) + return json.dumps(converted) + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + internalList = [] + for item in self._data: + item._build_rec_dict(naming_map, internalList) + if len(internalList) > 0: + first_rec = internalList[0] + else: + first_rec = {} + internalList.append(first_rec) + + if self.name: + first_rec[naming_map["bn"]] = self.name + if self.base_value: + first_rec[naming_map["bv"]] = self.base_value + if self.base_unit: + first_rec[naming_map["bu"]] = self.base_unit + if self.base_sum: + first_rec[naming_map["bs"]] = self.base_sum + if self.base_time: + first_rec[naming_map["bt"]] = self.base_time + appendTo.extend(internalList) + + def from_cbor(self, data): + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + records = cbor2.loads(data) # load the raw senml data + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + self._process_incomming_data(records, naming_map) + + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + converted = [] + self._build_rec_dict(naming_map, converted) + return cbor2.dumps(converted) + + def add(self, item): + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if item._parent is not None: + raise Exception("item is already part of a pack") + + self._data.append(item) + item._parent = self + + def remove(self, item): + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if not item._parent == self: + raise Exception("item is not part of this pack") + + self._data.remove(item) + item._parent = None + + def clear(self): + """ + clear the list of the pack + :return: None + """ + for item in self._data: + item._parent = None + self._data = [] diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_pack.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_pack.pyi new file mode 100644 index 000000000..57a0cf547 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_pack.pyi @@ -0,0 +1,143 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase +from senml.senml_record import SenmlRecord as SenmlRecord + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + _list: Incomplete + _index: int + def __init__(self, list) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings: Incomplete + _data: Incomplete + name: Incomplete + _base_value: Incomplete + _base_time: Incomplete + _base_sum: Incomplete + base_unit: Incomplete + _parent: Incomplete + actuate: Incomplete + def __init__(self, name, callback=None) -> None: + """ + initialize the object + :param name: {string} the name of the pack + """ + def __iter__(self): ... + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + @base_value.setter + def base_value(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + @base_sum.setter + def base_sum(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_time(self): ... + @base_time.setter + def base_time(self, value) -> None: ... + def _check_value_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def from_json(self, data) -> None: + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + def _process_incomming_data(self, records, naming_map) -> None: + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + def do_actuate(self, raw, naming_map, device=None) -> None: + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + def from_cbor(self, data) -> None: + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + def add(self, item) -> None: + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + def remove(self, item) -> None: + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + def clear(self) -> None: + """ + clear the list of the pack + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_record.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_record.py new file mode 100644 index 000000000..b5b07b0bc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_record.py @@ -0,0 +1,240 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import binascii +from senml.senml_base import SenmlBase + + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + def __init__(self, name, **kwargs): + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + self.__parent = None # using double __ cause it's a field for an internal property + self._unit = None # declare and init internal fields + self._value = None + self._time = None + self._sum = None + self._update_time = None + + self._parent = None # internal reference to the parent object + self.name = name + self.unit = kwargs.get("unit", None) + self.value = kwargs.get("value", None) + self.time = kwargs.get("time", None) + self.sum = kwargs.get("sum", None) + self.update_time = kwargs.get("update_time", None) + self.actuate = kwargs.get("callback", None) # actuate callback function + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + def _check_value_type(self, value): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not ( + isinstance(value, bool) + or isinstance(value, int) + or isinstance(value, float) + or isinstance(value, bytearray) + or isinstance(value, str) + ): + raise Exception("invalid type for value, only numbers, strings, boolean and byte arrays allowed") + + def _check_number_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + @property + def value(self): + """get the value currently assigned to the object""" + return self._value + + @value.setter + def value(self, value): + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + self._check_value_type(value) + self._value = value + + @property + def time(self): + return self._time + + @time.setter + def time(self, value): + self._check_number_type(value, "time") + self._time = value + + @property + def update_time(self): + return self._update_time + + @update_time.setter + def update_time(self, value): + self._check_number_type(value, "update_time") + self._update_time = value + + @property + def sum(self): + return self._sum + + @sum.setter + def sum(self, value): + self._check_number_type(value, "sum") + self._sum = value + + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + return self.__parent + + @_parent.setter + def _parent(self, value): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + self.__parent = value + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + result = {} + + if self.name: + result[naming_map["n"]] = self.name + + if self._sum: + if self._parent and self._parent.base_sum: + result[naming_map["s"]] = self._sum - self._parent.base_sum + else: + result[naming_map["s"]] = self._sum + elif isinstance(self._value, bool): + result[naming_map["vb"]] = self._value + elif isinstance(self._value, int) or isinstance(self._value, float): + if self._parent and self._parent.base_value: + result[naming_map["v"]] = self._value - self._parent.base_value + else: + result[naming_map["v"]] = self._value + elif isinstance(self._value, str): + result[naming_map["vs"]] = self._value + elif isinstance(self._value, bytearray): + if naming_map["vd"] == "vd": # neeed to make a distinction between json (needs base64) and cbor (needs binary) + result[naming_map["vd"]] = binascii.b2a_base64(self._value, newline=False).decode("utf8") + else: + result[naming_map["vd"]] = self._value + else: + raise Exception("sum or value of type bootl, number, string or byte-array is required") + + if self._time: + if self._parent and self._parent.base_time: + result[naming_map["t"]] = self._time - self._parent.base_time + else: + result[naming_map["t"]] = self._time + + if self.unit: + result[naming_map["u"]] = self.unit + + if self._update_time: + if self._parent and self._parent.base_time: + result[naming_map["ut"]] = self._update_time - self._parent.base_time + else: + result[naming_map["ut"]] = self._update_time + + appendTo.append(result) + + def _from_raw(self, raw, naming_map): + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + if naming_map["v"] in raw: + val = raw[naming_map["v"]] + if self._parent and self._parent.base_value: + val += self._parent.base_value + elif naming_map["vs"] in raw: + val = raw[naming_map["vs"]] + elif naming_map["vb"] in raw: + val = raw[naming_map["vb"]] + elif naming_map["vd"] in raw: + val = binascii.a2b_base64(raw[naming_map["vb"]]) + else: + val = None + self.value = val + + def do_actuate(self, raw, naming_map): + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ + self._from_raw(raw, naming_map) + if self.actuate: + self.actuate(self) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_record.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_record.pyi new file mode 100644 index 000000000..61c0c7c05 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_record.pyi @@ -0,0 +1,104 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + __parent: Incomplete + _unit: Incomplete + _value: Incomplete + _time: Incomplete + _sum: Incomplete + _update_time: Incomplete + name: Incomplete + unit: Incomplete + actuate: Incomplete + def __init__(self, name, **kwargs) -> None: + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + def _check_value_type(self, value) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def _check_number_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + @property + def value(self): + """get the value currently assigned to the object""" + @value.setter + def value(self, value) -> None: + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + @property + def time(self): ... + @time.setter + def time(self, value) -> None: ... + @property + def update_time(self): ... + @update_time.setter + def update_time(self, value) -> None: ... + @property + def sum(self): ... + @sum.setter + def sum(self, value) -> None: ... + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + @_parent.setter + def _parent(self, value) -> None: + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + def _from_raw(self, raw, naming_map) -> None: + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + def do_actuate(self, raw, naming_map) -> None: + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_unit.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_unit.py new file mode 100644 index 000000000..bf7753c4d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_unit.py @@ -0,0 +1,89 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +def enum(**enums): + return type("Enum", (), enums) + + +SenmlUnits = enum( + SENML_UNIT_METER="m", + SENML_UNIT_KILOGRAM="kg", + SENML_UNIT_GRAM="g", + SENML_UNIT_SECOND="s", + SENML_UNIT_AMPERE="A", + SENML_UNIT_KELVIN="K", + SENML_UNIT_CANDELA="cd", + SENML_UNIT_MOLE="mol", + SENML_UNIT_HERTZ="Hz", + SENML_UNIT_RADIAN="rad", + SENML_UNIT_STERADIAN="sr", + SENML_UNIT_NEWTON="N", + SENML_UNIT_PASCAL="Pa", + SENML_UNIT_JOULE="J", + SENML_UNIT_WATT="W", + SENML_UNIT_COULOMB="C", + SENML_UNIT_VOLT="V", + SENML_UNIT_FARAD="F", + SENML_UNIT_OHM="Ohm", + SENML_UNIT_SIEMENS="S", + SENML_UNIT_WEBER="Wb", + SENML_UNIT_TESLA="T", + SENML_UNIT_HENRY="H", + SENML_UNIT_DEGREES_CELSIUS="Cel", + SENML_UNIT_LUMEN="lm", + SENML_UNIT_LUX="lx", + SENML_UNIT_BECQUEREL="Bq", + SENML_UNIT_GRAY="Gy", + SENML_UNIT_SIEVERT="Sv", + SENML_UNIT_KATAL="kat", + SENML_UNIT_SQUARE_METER="m2", + SENML_UNIT_CUBIC_METER="m3", + SENML_UNIT_LITER="l", + SENML_UNIT_VELOCITY="m/s", + SENML_UNIT_ACCELERATION="m/s2", + SENML_UNIT_CUBIC_METER_PER_SECOND="m3/s", + SENML_UNIT_LITER_PER_SECOND="l/s", + SENML_UNIT_WATT_PER_SQUARE_METER="W/m2", + SENML_UNIT_CANDELA_PER_SQUARE_METER="cd/m2", + SENML_UNIT_BIT="bit", + SENML_UNIT_BIT_PER_SECOND="bit/s", + SENML_UNIT_DEGREES_LATITUDE="lat", + SENML_UNIT_DEGREES_LONGITUDE="lon", + SENML_UNIT_PH="pH", + SENML_UNIT_DECIBEL="db", + SENML_UNIT_DECIBEL_RELATIVE_TO_1_W="dBW", + SENML_UNIT_BEL="Bspl", + SENML_UNIT_COUNTER="count", + SENML_UNIT_RATIO="//", + SENML_UNIT_RELATIVE_HUMIDITY="%RH", + SENML_UNIT_PERCENTAGE_REMAINING_BATTERY_LEVEL="%EL", + SENML_UNIT_SECONDS_REMAINING_BATTERY_LEVEL="EL", + SENML_UNIT_EVENT_RATE_PER_SECOND="1/s", + SENML_UNIT_EVENT_RATE_PER_MINUTE="1/min", + SENML_UNIT_BPM="beat/min", + SENML_UNIT_BEATS="beats", + SENML_UNIT_SIEMENS_PER_METER="S/m", +) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_unit.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_unit.pyi new file mode 100644 index 000000000..6b3e7ae68 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/senml/senml_unit.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +def enum(**enums): ... + +SenmlUnits: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/time.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/time.py new file mode 100644 index 000000000..f79ab8a3b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/time.py @@ -0,0 +1,79 @@ +from utime import * +from micropython import const + +_TS_YEAR = 0 +_TS_MON = 1 +_TS_MDAY = 2 +_TS_HOUR = 3 +_TS_MIN = 4 +_TS_SEC = 5 +_TS_WDAY = 6 +_TS_YDAY = 7 +_TS_ISDST = 8 + +_WDAY = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") +_MDAY = const( + ( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ) +) + + +def strftime(datefmt, ts): + from io import StringIO + + fmtsp = False + ftime = StringIO() + for k in datefmt: + if fmtsp: + if k == "a": + ftime.write(_WDAY[ts[_TS_WDAY]][0:3]) + elif k == "A": + ftime.write(_WDAY[ts[_TS_WDAY]]) + elif k == "b": + ftime.write(_MDAY[ts[_TS_MON] - 1][0:3]) + elif k == "B": + ftime.write(_MDAY[ts[_TS_MON] - 1]) + elif k == "d": + ftime.write("%02d" % ts[_TS_MDAY]) + elif k == "H": + ftime.write("%02d" % ts[_TS_HOUR]) + elif k == "I": + ftime.write("%02d" % (ts[_TS_HOUR] % 12)) + elif k == "j": + ftime.write("%03d" % ts[_TS_YDAY]) + elif k == "m": + ftime.write("%02d" % ts[_TS_MON]) + elif k == "M": + ftime.write("%02d" % ts[_TS_MIN]) + elif k == "P": + ftime.write("AM" if ts[_TS_HOUR] < 12 else "PM") + elif k == "S": + ftime.write("%02d" % ts[_TS_SEC]) + elif k == "w": + ftime.write(str(ts[_TS_WDAY])) + elif k == "y": + ftime.write("%02d" % (ts[_TS_YEAR] % 100)) + elif k == "Y": + ftime.write(str(ts[_TS_YEAR])) + else: + ftime.write(k) + fmtsp = False + elif k == "%": + fmtsp = True + else: + ftime.write(k) + val = ftime.getvalue() + ftime.close() + return val diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/time.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/time.pyi new file mode 100644 index 000000000..26b0e4b08 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/time.pyi @@ -0,0 +1,59 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. +""" + +from __future__ import annotations +from utime import * +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TS_YEAR: int +_TS_MON: int +_TS_MDAY: int +_TS_HOUR: int +_TS_MIN: int +_TS_SEC: int +_TS_WDAY: int +_TS_YDAY: int +_TS_ISDST: int +_WDAY: Incomplete +_MDAY: Incomplete +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def strftime(datefmt, ts): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/ARDUINO_NANO_ESP32/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/modules.json new file mode 100644 index 000000000..b1cc8ca1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/modules.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "GENERIC", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/GENERIC/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lilygo_oled.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lilygo_oled.py new file mode 100644 index 000000000..98ea0adcb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lilygo_oled.py @@ -0,0 +1,41 @@ +from time import sleep_ms +from ssd1306 import SSD1306_I2C +import network + + +class OLED(SSD1306_I2C): + def __init__(self, i2c, rstpin): + # Initialize the OLED display + if rstpin is not None: + rstpin.value(0) + sleep_ms(50) + rstpin.value(1) # must be held high after initialization + super().__init__(128, 32, i2c) + + def test(self): + self.fill(0) + self.fill_rect(0, 0, 32, 32, 1) + self.fill_rect(2, 2, 28, 28, 0) + self.vline(9, 8, 22, 1) + self.vline(16, 2, 22, 1) + self.vline(23, 8, 22, 1) + self.fill_rect(26, 24, 2, 4, 1) + self.text("MicroPython", 40, 0, 1) + self.text("SSD1306", 40, 12, 1) + self.text("OLED 128x32", 40, 24, 1) + self.show() + + def display_wifi(self): + self.fill(0) + self.text("Scan...", 0, 0, 1) + self.show() + + sta_if = network.WLAN(network.WLAN.IF_STA) + sta_if.active(True) + _wifi = sta_if.scan() + + self.fill(0) + self.text(str(len(_wifi)) + " Networks", 0, 0, 1) + self.text(str(_wifi[0][3]) + " " + (_wifi[0][0]).decode("utf-8"), 0, 12, 1) + self.text(str(_wifi[1][3]) + " " + (_wifi[1][0]).decode("utf-8"), 0, 24, 1) + self.show() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lilygo_oled.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lilygo_oled.pyi new file mode 100644 index 000000000..56e16f025 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lilygo_oled.pyi @@ -0,0 +1,6 @@ +from ssd1306 import SSD1306_I2C + +class OLED(SSD1306_I2C): + def __init__(self, i2c, rstpin) -> None: ... + def test(self) -> None: ... + def display_wifi(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lora32.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lora32.py new file mode 100644 index 000000000..250c1b52f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lora32.py @@ -0,0 +1,81 @@ +"""LILYGO TTGO LoRa32 MicroPython Helper Library.""" + +from machine import Pin, SoftI2C, Signal + +from lilygo_oled import OLED + +from micropython import const + + +class Lora32Base: + """Base class defining common pins.""" + + def __init__(self, define_helpers=True): + # LORA + self.LORA_MOSI = 27 + self.LORA_MISO = 19 + self.LORA_SCLK = 5 + self.LORA_CS = 18 + self.LORA_DIO = 26 + self.LORA_RST = 23 + + # DAC + self.DAC1 = 26 + + # LED + self.LED = 25 + + # OLED + self.OLED_SDA = 21 + self.OLED_SCL = 22 + self.OLED_RST = None + + if define_helpers: + self.create_helpers() + + def create_helpers(self): + self.led = Pin(self.LED, Pin.OUT) + self.i2c = SoftI2C(scl=Pin(self.OLED_SCL), sda=Pin(self.OLED_SDA)) + rstpin = self.OLED_RST is not None and Pin(self.OLED_RST, Pin.OUT) or None + self.oled = OLED(self.i2c, rstpin) + + +class Lora32v1_0(Lora32Base): + """Device Support for LILYGO TTGO LoRa32 v1.0.""" + + def __init__(self): + super().__init__(define_helpers=False) + + # v1.0 has different pins for the following + self.LORA_RST = 14 + self.OLED_SDA = 4 + self.OLED_SCL = 15 + + # Also has a reset for the OLED that the others don't have + self.OLED_RST = 16 + + super().create_helpers() + + +class Lora32v1_2(Lora32Base): + """Device Support for LILYGO TTGO LoRa32 v1.2 (T-Fox).""" + + def __init__(self): + super().__init__() + + # v1.2 Has a DS3231 RTC + self.DS3231_SDA = 21 + self.DS3231_SCL = 22 + + +class Lora32(Lora32Base): + """Device Support for LILYGO TTGO LoRa32 v1.6 and v2.0.""" + + def __init__(self): + super().__init__() + + # v1.6 and v2.0 support an SDCard + self.SD_CS = 13 + self.SD_MOSI = 15 + self.SD_MISO = 2 + self.SD_SCLK = 14 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lora32.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lora32.pyi new file mode 100644 index 000000000..654fff333 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/lora32.pyi @@ -0,0 +1,48 @@ +from _typeshed import Incomplete +from machine import Signal as Signal +from micropython import const as const + +class Lora32Base: + """Base class defining common pins.""" + + LORA_MOSI: int + LORA_MISO: int + LORA_SCLK: int + LORA_CS: int + LORA_DIO: int + LORA_RST: int + DAC1: int + LED: int + OLED_SDA: int + OLED_SCL: int + OLED_RST: Incomplete + def __init__(self, define_helpers: bool = True) -> None: ... + led: Incomplete + i2c: Incomplete + oled: Incomplete + def create_helpers(self) -> None: ... + +class Lora32v1_0(Lora32Base): + """Device Support for LILYGO TTGO LoRa32 v1.0.""" + + LORA_RST: int + OLED_SDA: int + OLED_SCL: int + OLED_RST: int + def __init__(self) -> None: ... + +class Lora32v1_2(Lora32Base): + """Device Support for LILYGO TTGO LoRa32 v1.2 (T-Fox).""" + + DS3231_SDA: int + DS3231_SCL: int + def __init__(self) -> None: ... + +class Lora32(Lora32Base): + """Device Support for LILYGO TTGO LoRa32 v1.6 and v2.0.""" + + SD_CS: int + SD_MOSI: int + SD_MISO: int + SD_SCLK: int + def __init__(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/modules.json new file mode 100644 index 000000000..43309ff27 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/modules.json @@ -0,0 +1,120 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "LILYGO_TTGO_LORA32", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "lilygo_oled.py", + "module": "lilygo_oled" + }, + { + "file": "lora32.py", + "module": "lora32" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssd1306.py", + "module": "ssd1306" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssd1306.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssd1306.py new file mode 100644 index 000000000..ec511555e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssd1306.py @@ -0,0 +1,164 @@ +# MicroPython SSD1306 OLED driver, I2C and SPI interfaces + +from micropython import const +import framebuf + + +# register definitions +SET_CONTRAST = 0x81 +SET_ENTIRE_ON = 0xA4 +SET_NORM_INV = 0xA6 +SET_DISP = 0xAE +SET_MEM_ADDR = 0x20 +SET_COL_ADDR = 0x21 +SET_PAGE_ADDR = 0x22 +SET_DISP_START_LINE = 0x40 +SET_SEG_REMAP = 0xA0 +SET_MUX_RATIO = 0xA8 +SET_IREF_SELECT = 0xAD +SET_COM_OUT_DIR = 0xC0 +SET_DISP_OFFSET = 0xD3 +SET_COM_PIN_CFG = 0xDA +SET_DISP_CLK_DIV = 0xD5 +SET_PRECHARGE = 0xD9 +SET_VCOM_DESEL = 0xDB +SET_CHARGE_PUMP = 0x8D + + +# Subclassing FrameBuffer provides support for graphics primitives +# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html +class SSD1306(framebuf.FrameBuffer): + def __init__(self, width, height, external_vcc): + self.width = width + self.height = height + self.external_vcc = external_vcc + self.pages = self.height // 8 + self.buffer = bytearray(self.pages * self.width) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + self.init_display() + + def init_display(self): + for cmd in ( + SET_DISP, # display off + # address setting + SET_MEM_ADDR, + 0x00, # horizontal + # resolution and layout + SET_DISP_START_LINE, # start at line 0 + SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 + SET_MUX_RATIO, + self.height - 1, + SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 + SET_DISP_OFFSET, + 0x00, + SET_COM_PIN_CFG, + 0x02 if self.width > 2 * self.height else 0x12, + # timing and driving scheme + SET_DISP_CLK_DIV, + 0x80, + SET_PRECHARGE, + 0x22 if self.external_vcc else 0xF1, + SET_VCOM_DESEL, + 0x30, # 0.83*Vcc + # display + SET_CONTRAST, + 0xFF, # maximum + SET_ENTIRE_ON, # output follows RAM contents + SET_NORM_INV, # not inverted + SET_IREF_SELECT, + 0x30, # enable internal IREF during display on + # charge pump + SET_CHARGE_PUMP, + 0x10 if self.external_vcc else 0x14, + SET_DISP | 0x01, # display on + ): # on + self.write_cmd(cmd) + self.fill(0) + self.show() + + def poweroff(self): + self.write_cmd(SET_DISP) + + def poweron(self): + self.write_cmd(SET_DISP | 0x01) + + def contrast(self, contrast): + self.write_cmd(SET_CONTRAST) + self.write_cmd(contrast) + + def invert(self, invert): + self.write_cmd(SET_NORM_INV | (invert & 1)) + + def rotate(self, rotate): + self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3)) + self.write_cmd(SET_SEG_REMAP | (rotate & 1)) + + def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width != 128: + # narrow displays use centred columns + col_offset = (128 - self.width) // 2 + x0 += col_offset + x1 += col_offset + self.write_cmd(SET_COL_ADDR) + self.write_cmd(x0) + self.write_cmd(x1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + self.write_data(self.buffer) + + +class SSD1306_I2C(SSD1306): + def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): + self.i2c = i2c + self.addr = addr + self.temp = bytearray(2) + self.write_list = [b"\x40", None] # Co=0, D/C#=1 + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.temp[0] = 0x80 # Co=1, D/C#=0 + self.temp[1] = cmd + self.i2c.writeto(self.addr, self.temp) + + def write_data(self, buf): + self.write_list[1] = buf + self.i2c.writevto(self.addr, self.write_list) + + +class SSD1306_SPI(SSD1306): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): + self.rate = 10 * 1024 * 1024 + dc.init(dc.OUT, value=0) + res.init(res.OUT, value=0) + cs.init(cs.OUT, value=1) + self.spi = spi + self.dc = dc + self.res = res + self.cs = cs + import time + + self.res(1) + time.sleep_ms(1) + self.res(0) + time.sleep_ms(10) + self.res(1) + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(0) + self.cs(0) + self.spi.write(bytearray([cmd])) + self.cs(1) + + def write_data(self, buf): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(1) + self.cs(0) + self.spi.write(buf) + self.cs(1) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssd1306.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssd1306.pyi new file mode 100644 index 000000000..ca4f897fd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssd1306.pyi @@ -0,0 +1,56 @@ +import framebuf +from _typeshed import Incomplete +from micropython import const as const + +SET_CONTRAST: int +SET_ENTIRE_ON: int +SET_NORM_INV: int +SET_DISP: int +SET_MEM_ADDR: int +SET_COL_ADDR: int +SET_PAGE_ADDR: int +SET_DISP_START_LINE: int +SET_SEG_REMAP: int +SET_MUX_RATIO: int +SET_IREF_SELECT: int +SET_COM_OUT_DIR: int +SET_DISP_OFFSET: int +SET_COM_PIN_CFG: int +SET_DISP_CLK_DIV: int +SET_PRECHARGE: int +SET_VCOM_DESEL: int +SET_CHARGE_PUMP: int + +class SSD1306(framebuf.FrameBuffer): + width: Incomplete + height: Incomplete + external_vcc: Incomplete + pages: Incomplete + buffer: Incomplete + def __init__(self, width, height, external_vcc) -> None: ... + def init_display(self) -> None: ... + def poweroff(self) -> None: ... + def poweron(self) -> None: ... + def contrast(self, contrast) -> None: ... + def invert(self, invert) -> None: ... + def rotate(self, rotate) -> None: ... + def show(self) -> None: ... + +class SSD1306_I2C(SSD1306): + i2c: Incomplete + addr: Incomplete + temp: Incomplete + write_list: Incomplete + def __init__(self, width, height, i2c, addr: int = 60, external_vcc: bool = False) -> None: ... + def write_cmd(self, cmd) -> None: ... + def write_data(self, buf) -> None: ... + +class SSD1306_SPI(SSD1306): + rate: Incomplete + spi: Incomplete + dc: Incomplete + res: Incomplete + cs: Incomplete + def __init__(self, width, height, spi, dc, res, cs, external_vcc: bool = False) -> None: ... + def write_cmd(self, cmd) -> None: ... + def write_data(self, buf) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LILYGO_TTGO_LORA32/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/c3mini.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/c3mini.py new file mode 100644 index 000000000..97b1b7e35 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/c3mini.py @@ -0,0 +1,26 @@ +# LOLIN C3 MINI MicroPython Helper Library + +from micropython import const +from machine import Pin + +# Pin Assignments + +# SPI +SPI_MOSI = 4 +SPI_MISO = 3 +SPI_CLK = 2 + +# I2C +I2C_SDA = 8 +I2C_SCL = 10 + +# LED +LED = 7 + +# BUTTON +BUTTON = 0 + +# Built-in peripherals + +led = Pin(LED, Pin.OUT, value=0) +button = Pin(BUTTON, Pin.IN, Pin.PULL_UP) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/c3mini.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/c3mini.pyi new file mode 100644 index 000000000..af627f727 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/c3mini.pyi @@ -0,0 +1,12 @@ +from _typeshed import Incomplete +from micropython import const as const + +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int +LED: int +BUTTON: int +led: Incomplete +button: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/modules.json new file mode 100644 index 000000000..038942eae --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "LOLIN_C3_MINI", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "c3mini.py", + "module": "c3mini" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_C3_MINI/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/modules.json new file mode 100644 index 000000000..4f9a00418 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "LOLIN_S2_MINI", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "s2mini.py", + "module": "s2mini" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/s2mini.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/s2mini.py new file mode 100644 index 000000000..461e6c43f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/s2mini.py @@ -0,0 +1,31 @@ +# LOLIN S2 MINI MicroPython Helper Library + +from micropython import const +from machine import Pin + +# Pin Assignments + +# SPI +SPI_MOSI = 11 +SPI_MISO = 9 +SPI_CLK = 7 + +# I2C +I2C_SDA = 33 +I2C_SCL = 35 + +# DAC +DAC1 = 17 +DAC2 = 18 + +# LED +LED = 15 + +# BUTTON +BUTTON = 0 + +# Helper methods for built in sensors + +led = Pin(LED, Pin.OUT, value=0) + +button = Pin(BUTTON, Pin.IN, Pin.PULL_UP) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/s2mini.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/s2mini.pyi new file mode 100644 index 000000000..4b772f741 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/s2mini.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete +from micropython import const as const + +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int +DAC1: int +DAC2: int +LED: int +BUTTON: int +led: Incomplete +button: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_MINI/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/modules.json new file mode 100644 index 000000000..b2f4b0dc1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/modules.json @@ -0,0 +1,120 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "LOLIN_S2_PICO", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "s2pico.py", + "module": "s2pico" + }, + { + "file": "s2pico_oled.py", + "module": "s2pico_oled" + }, + { + "file": "ssd1306.py", + "module": "ssd1306" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico.py new file mode 100644 index 000000000..1b40b4300 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico.py @@ -0,0 +1,38 @@ +# LOLIN S2 PICO MicroPython Helper Library + +from micropython import const +from machine import Pin, I2C, Signal +from s2pico_oled import OLED + +# Pin Assignments + +# SPI +SPI_MOSI = 35 +SPI_MISO = 36 +SPI_CLK = 37 + +# I2C +I2C_SDA = 8 +I2C_SCL = 9 + +# DAC +DAC1 = 17 +DAC2 = 18 + +# LED +LED = 10 + +# OLED +OLED_RST = 18 + +# BUTTON +BUTTON = 0 + +# Helper methods for built in sensors + +led = Signal(LED, Pin.OUT, value=0, invert=True) + +button = Pin(BUTTON, Pin.IN, Pin.PULL_UP) + +i2c = I2C(0) +oled = OLED(i2c, Pin(OLED_RST)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico.pyi new file mode 100644 index 000000000..cb6a5ccd3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete +from micropython import const as const + +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int +DAC1: int +DAC2: int +LED: int +OLED_RST: int +BUTTON: int +led: Incomplete +button: Incomplete +i2c: Incomplete +oled: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico_oled.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico_oled.py new file mode 100644 index 000000000..58120d44a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico_oled.py @@ -0,0 +1,48 @@ +from time import sleep_ms +from ssd1306 import SSD1306_I2C +import network + + +class OLED(SSD1306_I2C): + def __init__(self, i2c, reset): + reset.init(reset.OUT, value=1) + self._reset = reset + self.reset(False) + super().__init__(128, 32, i2c) + + def reset(self, reinit=True): + self._reset(1) + sleep_ms(1) + self._reset(0) + sleep_ms(10) + self._reset(1) + if reinit: + self.init_display() + + def test(self): + self.fill(0) + self.fill_rect(0, 0, 32, 32, 1) + self.fill_rect(2, 2, 28, 28, 0) + self.vline(9, 8, 22, 1) + self.vline(16, 2, 22, 1) + self.vline(23, 8, 22, 1) + self.fill_rect(26, 24, 2, 4, 1) + self.text("MicroPython", 40, 0, 1) + self.text("SSD1306", 40, 12, 1) + self.text("OLED 128x32", 40, 24, 1) + self.show() + + def display_wifi(self): + self.fill(0) + self.text("Scan...", 0, 0, 1) + self.show() + + sta_if = network.WLAN(network.WLAN.IF_STA) + sta_if.active(True) + _wifi = sta_if.scan() + + self.fill(0) + self.text(str(len(_wifi)) + " Networks", 0, 0, 1) + self.text(str(_wifi[0][3]) + " " + (_wifi[0][0]).decode("utf-8"), 0, 12, 1) + self.text(str(_wifi[1][3]) + " " + (_wifi[1][0]).decode("utf-8"), 0, 24, 1) + self.show() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico_oled.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico_oled.pyi new file mode 100644 index 000000000..6ba0e9dbb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/s2pico_oled.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete +from ssd1306 import SSD1306_I2C + +class OLED(SSD1306_I2C): + _reset: Incomplete + def __init__(self, i2c, reset) -> None: ... + def reset(self, reinit: bool = True) -> None: ... + def test(self) -> None: ... + def display_wifi(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssd1306.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssd1306.py new file mode 100644 index 000000000..ec511555e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssd1306.py @@ -0,0 +1,164 @@ +# MicroPython SSD1306 OLED driver, I2C and SPI interfaces + +from micropython import const +import framebuf + + +# register definitions +SET_CONTRAST = 0x81 +SET_ENTIRE_ON = 0xA4 +SET_NORM_INV = 0xA6 +SET_DISP = 0xAE +SET_MEM_ADDR = 0x20 +SET_COL_ADDR = 0x21 +SET_PAGE_ADDR = 0x22 +SET_DISP_START_LINE = 0x40 +SET_SEG_REMAP = 0xA0 +SET_MUX_RATIO = 0xA8 +SET_IREF_SELECT = 0xAD +SET_COM_OUT_DIR = 0xC0 +SET_DISP_OFFSET = 0xD3 +SET_COM_PIN_CFG = 0xDA +SET_DISP_CLK_DIV = 0xD5 +SET_PRECHARGE = 0xD9 +SET_VCOM_DESEL = 0xDB +SET_CHARGE_PUMP = 0x8D + + +# Subclassing FrameBuffer provides support for graphics primitives +# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html +class SSD1306(framebuf.FrameBuffer): + def __init__(self, width, height, external_vcc): + self.width = width + self.height = height + self.external_vcc = external_vcc + self.pages = self.height // 8 + self.buffer = bytearray(self.pages * self.width) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + self.init_display() + + def init_display(self): + for cmd in ( + SET_DISP, # display off + # address setting + SET_MEM_ADDR, + 0x00, # horizontal + # resolution and layout + SET_DISP_START_LINE, # start at line 0 + SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 + SET_MUX_RATIO, + self.height - 1, + SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 + SET_DISP_OFFSET, + 0x00, + SET_COM_PIN_CFG, + 0x02 if self.width > 2 * self.height else 0x12, + # timing and driving scheme + SET_DISP_CLK_DIV, + 0x80, + SET_PRECHARGE, + 0x22 if self.external_vcc else 0xF1, + SET_VCOM_DESEL, + 0x30, # 0.83*Vcc + # display + SET_CONTRAST, + 0xFF, # maximum + SET_ENTIRE_ON, # output follows RAM contents + SET_NORM_INV, # not inverted + SET_IREF_SELECT, + 0x30, # enable internal IREF during display on + # charge pump + SET_CHARGE_PUMP, + 0x10 if self.external_vcc else 0x14, + SET_DISP | 0x01, # display on + ): # on + self.write_cmd(cmd) + self.fill(0) + self.show() + + def poweroff(self): + self.write_cmd(SET_DISP) + + def poweron(self): + self.write_cmd(SET_DISP | 0x01) + + def contrast(self, contrast): + self.write_cmd(SET_CONTRAST) + self.write_cmd(contrast) + + def invert(self, invert): + self.write_cmd(SET_NORM_INV | (invert & 1)) + + def rotate(self, rotate): + self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3)) + self.write_cmd(SET_SEG_REMAP | (rotate & 1)) + + def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width != 128: + # narrow displays use centred columns + col_offset = (128 - self.width) // 2 + x0 += col_offset + x1 += col_offset + self.write_cmd(SET_COL_ADDR) + self.write_cmd(x0) + self.write_cmd(x1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + self.write_data(self.buffer) + + +class SSD1306_I2C(SSD1306): + def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): + self.i2c = i2c + self.addr = addr + self.temp = bytearray(2) + self.write_list = [b"\x40", None] # Co=0, D/C#=1 + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.temp[0] = 0x80 # Co=1, D/C#=0 + self.temp[1] = cmd + self.i2c.writeto(self.addr, self.temp) + + def write_data(self, buf): + self.write_list[1] = buf + self.i2c.writevto(self.addr, self.write_list) + + +class SSD1306_SPI(SSD1306): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): + self.rate = 10 * 1024 * 1024 + dc.init(dc.OUT, value=0) + res.init(res.OUT, value=0) + cs.init(cs.OUT, value=1) + self.spi = spi + self.dc = dc + self.res = res + self.cs = cs + import time + + self.res(1) + time.sleep_ms(1) + self.res(0) + time.sleep_ms(10) + self.res(1) + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(0) + self.cs(0) + self.spi.write(bytearray([cmd])) + self.cs(1) + + def write_data(self, buf): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(1) + self.cs(0) + self.spi.write(buf) + self.cs(1) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssd1306.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssd1306.pyi new file mode 100644 index 000000000..ca4f897fd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssd1306.pyi @@ -0,0 +1,56 @@ +import framebuf +from _typeshed import Incomplete +from micropython import const as const + +SET_CONTRAST: int +SET_ENTIRE_ON: int +SET_NORM_INV: int +SET_DISP: int +SET_MEM_ADDR: int +SET_COL_ADDR: int +SET_PAGE_ADDR: int +SET_DISP_START_LINE: int +SET_SEG_REMAP: int +SET_MUX_RATIO: int +SET_IREF_SELECT: int +SET_COM_OUT_DIR: int +SET_DISP_OFFSET: int +SET_COM_PIN_CFG: int +SET_DISP_CLK_DIV: int +SET_PRECHARGE: int +SET_VCOM_DESEL: int +SET_CHARGE_PUMP: int + +class SSD1306(framebuf.FrameBuffer): + width: Incomplete + height: Incomplete + external_vcc: Incomplete + pages: Incomplete + buffer: Incomplete + def __init__(self, width, height, external_vcc) -> None: ... + def init_display(self) -> None: ... + def poweroff(self) -> None: ... + def poweron(self) -> None: ... + def contrast(self, contrast) -> None: ... + def invert(self, invert) -> None: ... + def rotate(self, rotate) -> None: ... + def show(self) -> None: ... + +class SSD1306_I2C(SSD1306): + i2c: Incomplete + addr: Incomplete + temp: Incomplete + write_list: Incomplete + def __init__(self, width, height, i2c, addr: int = 60, external_vcc: bool = False) -> None: ... + def write_cmd(self, cmd) -> None: ... + def write_data(self, buf) -> None: ... + +class SSD1306_SPI(SSD1306): + rate: Incomplete + spi: Incomplete + dc: Incomplete + res: Incomplete + cs: Incomplete + def __init__(self, width, height, spi, dc, res, cs, external_vcc: bool = False) -> None: ... + def write_cmd(self, cmd) -> None: ... + def write_data(self, buf) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/LOLIN_S2_PICO/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/atom.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/atom.py new file mode 100644 index 000000000..d4c56edb6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/atom.py @@ -0,0 +1,75 @@ +# M5Stack ATOM MicroPython Helper Library +# MIT license; Copyright (c) 2021 IAMLIUBO work for M5STACK +# +# Hardware details: +# ATOM Lite https://docs.m5stack.com/en/core/atom_lite +# ATOM Matrix https://docs.m5stack.com/en/core/atom_matrix + +from micropython import const +from machine import Pin +import neopixel + +# M5STACK ATOM Hardware Pin Assignments +""" + FRONT + |3V3| +|G21| IR G12 |G22| +|G25| BTN G39 |G19| +| 5V| WS2812 G27 |G23| +|GNG| MPU G21 G25 |G33| + G32 G26 5V GND + Grove Port +""" + +# WS2812 +WS2812_PIN = 27 + +# Button +BUTTON_PIN = 39 + +# IR +IR_PIN = 12 + +# I2C +I2C0_SCL_PIN = 21 +I2C0_SDA_PIN = 25 + +# Grove port +GROVE_PORT_PIN = (26), 32 + + +class ATOM: + def __init__(self, np_n): + self._np = neopixel.NeoPixel(pin=Pin(WS2812_PIN), n=np_n) + self._btn = Pin(BUTTON_PIN, Pin.IN, Pin.PULL_UP) + + def get_button_status(self): + return self._btn.value() + + def set_button_callback(self, cb): + self._btn.irq(trigger=Pin.IRQ_FALLING, handler=cb) + + def set_pixel_color(self, num, r, g, b): + if num <= self._np.n: + self._np[num] = [r, g, b] + self._np.write() + + def get_pixel_color(self, num): + if num <= self._np.n: + return self._np[num] + + def set_pixels_color(self, r, g, b): + self._np.fill([r, g, b]) + self._np.write() + + +class Lite(ATOM): + # WS2812 number: 1 + def __init__(self): + super(Lite, self).__init__(np_n=1) + + +class Matrix(ATOM): + # WS2812 number: 25 + def __init__(self): + super(Matrix, self).__init__(np_n=25) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/atom.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/atom.pyi new file mode 100644 index 000000000..2ad2d6153 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/atom.pyi @@ -0,0 +1,25 @@ +from _typeshed import Incomplete +from micropython import const as const + +WS2812_PIN: int +BUTTON_PIN: int +IR_PIN: int +I2C0_SCL_PIN: int +I2C0_SDA_PIN: int +GROVE_PORT_PIN: Incomplete + +class ATOM: + _np: Incomplete + _btn: Incomplete + def __init__(self, np_n) -> None: ... + def get_button_status(self): ... + def set_button_callback(self, cb) -> None: ... + def set_pixel_color(self, num, r, g, b) -> None: ... + def get_pixel_color(self, num): ... + def set_pixels_color(self, r, g, b) -> None: ... + +class Lite(ATOM): + def __init__(self) -> None: ... + +class Matrix(ATOM): + def __init__(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/modules.json new file mode 100644 index 000000000..8ff8c3659 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "M5STACK_ATOM", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "atom.py", + "module": "atom" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/M5STACK_ATOM/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/modules.json new file mode 100644 index 000000000..9a0b61b2e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "SPARKFUN_IOT_REDBOARD_ESP32", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "sdcard.py", + "module": "sdcard" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/sdcard.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/sdcard.py new file mode 100644 index 000000000..1a271b537 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/sdcard.py @@ -0,0 +1,306 @@ +""" +MicroPython driver for SD cards using SPI bus. + +Requires an SPI bus and a CS pin. Provides readblocks and writeblocks +methods so the device can be mounted as a filesystem. + +Example usage on pyboard: + + import pyb, sdcard, os + sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) + pyb.mount(sd, '/sd2') + os.listdir('/') + +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) + os.mount(sd, '/sd') + os.listdir('/') + +""" + +from micropython import const +import time + + +_CMD_TIMEOUT = 100 + +_R1_IDLE_STATE = 1 << 0 +# R1_ERASE_RESET = 1 << 1 +_R1_ILLEGAL_COMMAND = 1 << 2 +# R1_COM_CRC_ERROR = 1 << 3 +# R1_ERASE_SEQUENCE_ERROR = 1 << 4 +# R1_ADDRESS_ERROR = 1 << 5 +# R1_PARAMETER_ERROR = 1 << 6 +_TOKEN_CMD25 = 0xFC +_TOKEN_STOP_TRAN = 0xFD +_TOKEN_DATA = 0xFE + + +class SDCard: + def __init__(self, spi, cs, baudrate=1320000): + self.spi = spi + self.cs = cs + + self.cmdbuf = bytearray(6) + self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) + for i in range(512): + self.dummybuf[i] = 0xFF + self.dummybuf_memoryview = memoryview(self.dummybuf) + + # initialise the card + self.init_card(baudrate) + + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + + def init_card(self, baudrate): + # init CS pin + self.cs.init(self.cs.OUT, value=1) + + # init SPI bus; use low data rate for initialisation + self.init_spi(100000) + + # clock card at least 100 cycles with cs high + for i in range(16): + self.spi.write(b"\xff") + + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) + for _ in range(5): + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: + break + else: + raise OSError("no SD card") + + # CMD8: determine card version + r = self.cmd(8, 0x01AA, 0x87, 4) + if r == _R1_IDLE_STATE: + self.init_card_v2() + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): + self.init_card_v1() + else: + raise OSError("couldn't determine SD card version") + + # get the number of sectors + # CMD9: response R2 (R1 byte + 16-byte block read) + if self.cmd(9, 0, 0, 0, False) != 0: + raise OSError("no response from SD card") + csd = bytearray(16) + self.readinto(csd) + if csd[0] & 0xC0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 + elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 + c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 + read_bl_len = csd[5] & 0b1111 + capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) + self.sectors = capacity // 512 + else: + raise OSError("SD card CSD format not supported") + # print('sectors', self.sectors) + + # CMD16: set block length to 512 bytes + if self.cmd(16, 512, 0) != 0: + raise OSError("can't set 512 block size") + + # set to high data rate now that it's initialised + self.init_spi(baudrate) + + def init_card_v1(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(55, 0, 0) + if self.cmd(41, 0, 0) == 0: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + # print("[SDCard] v1 card") + return + raise OSError("timeout waiting for v1 card") + + def init_card_v2(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(58, 0, 0, 4) + self.cmd(55, 0, 0) + if self.cmd(41, 0x40000000, 0) == 0: + self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte + ocr = self.tokenbuf[0] # get first byte of response, which is OCR + if not ocr & 0x40: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + else: + # SDHC/SDXC card, uses block addressing in read/write/erase commands + self.cdv = 1 + # print("[SDCard] v2 card") + return + raise OSError("timeout waiting for v2 card") + + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): + self.cs(0) + + # create and send the command + buf = self.cmdbuf + buf[0] = 0x40 | cmd + buf[1] = arg >> 24 + buf[2] = arg >> 16 + buf[3] = arg >> 8 + buf[4] = arg + buf[5] = crc + self.spi.write(buf) + + if skip1: + self.spi.readinto(self.tokenbuf, 0xFF) + + # wait for the response (response[7] == 0) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + response = self.tokenbuf[0] + if not (response & 0x80): + # this could be a big-endian integer that we are getting here + # if final<0 then store the first byte to tokenbuf and discard the rest + if final < 0: + self.spi.readinto(self.tokenbuf, 0xFF) + final = -1 - final + for j in range(final): + self.spi.write(b"\xff") + if release: + self.cs(1) + self.spi.write(b"\xff") + return response + + # timeout + self.cs(1) + self.spi.write(b"\xff") + return -1 + + def readinto(self, buf): + self.cs(0) + + # read until start byte (0xff) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + if self.tokenbuf[0] == _TOKEN_DATA: + break + time.sleep_ms(1) + else: + self.cs(1) + raise OSError("timeout waiting for response") + + # read data + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[: len(buf)] + self.spi.write_readinto(mv, buf) + + # read checksum + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + self.cs(1) + self.spi.write(b"\xff") + + def write(self, token, buf): + self.cs(0) + + # send: start of block, data, checksum + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + # check the response + if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: + self.cs(1) + self.spi.write(b"\xff") + return + + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def write_token(self, token): + self.cs(0) + self.spi.read(1, token) + self.spi.write(b"\xff") + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0x00: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def readblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, "Buffer length is invalid" + if nblocks == 1: + # CMD17: set read address for single block + if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + # receive the data and release card + self.readinto(buf) + else: + # CMD18: set read address for multiple blocks + if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + offset = 0 + mv = memoryview(buf) + while nblocks: + # receive the data and release card + self.readinto(mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + if self.cmd(12, 0, 0xFF, skip1=True): + raise OSError(5) # EIO + + def writeblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks, err = divmod(len(buf), 512) + assert nblocks and not err, "Buffer length is invalid" + if nblocks == 1: + # CMD24: set write address for single block + if self.cmd(24, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + + # send the data + self.write(_TOKEN_DATA, buf) + else: + # CMD25: set write address for first block + if self.cmd(25, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + # send the data + offset = 0 + mv = memoryview(buf) + while nblocks: + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return self.sectors + if op == 5: # get block size in bytes + return 512 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/sdcard.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/sdcard.pyi new file mode 100644 index 000000000..3009717c8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/sdcard.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CMD_TIMEOUT: int +_R1_IDLE_STATE: Incomplete +_R1_ILLEGAL_COMMAND: Incomplete +_TOKEN_CMD25: int +_TOKEN_STOP_TRAN: int +_TOKEN_DATA: int + +class SDCard: + spi: Incomplete + cs: Incomplete + cmdbuf: Incomplete + dummybuf: Incomplete + tokenbuf: Incomplete + dummybuf_memoryview: Incomplete + def __init__(self, spi, cs, baudrate: int = 1320000) -> None: ... + def init_spi(self, baudrate) -> None: ... + sectors: Incomplete + def init_card(self, baudrate) -> None: ... + cdv: int + def init_card_v1(self) -> None: ... + def init_card_v2(self) -> None: ... + def cmd(self, cmd, arg, crc, final: int = 0, release: bool = True, skip1: bool = False): ... + def readinto(self, buf) -> None: ... + def write(self, token, buf) -> None: ... + def write_token(self, token) -> None: ... + def readblocks(self, block_num, buf) -> None: ... + def writeblocks(self, block_num, buf) -> None: ... + def ioctl(self, op, arg): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/SPARKFUN_IOT_REDBOARD_ESP32/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dotstar.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dotstar.py new file mode 100644 index 000000000..b16d1cde1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dotstar.py @@ -0,0 +1,225 @@ +# DotStar strip driver for MicroPython +# +# The MIT License (MIT) +# +# Copyright (c) 2016 Damien P. George (original Neopixel object) +# Copyright (c) 2017 Ladyada +# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries +# Copyright (c) 2019 Matt Trentini (porting back to MicroPython) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +START_HEADER_SIZE = 4 +LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits + +# Pixel color order constants +RGB = (0, 1, 2) +RBG = (0, 2, 1) +GRB = (1, 0, 2) +GBR = (1, 2, 0) +BRG = (2, 0, 1) +BGR = (2, 1, 0) + + +class DotStar: + """ + A sequence of dotstars. + + :param SPI spi: The SPI object to write output to. + :param int n: The number of dotstars in the chain + :param float brightness: Brightness of the pixels between 0.0 and 1.0 + :param bool auto_write: True if the dotstars should immediately change when + set. If False, `show` must be called explicitly. + :param tuple pixel_order: Set the pixel order on the strip - different + strips implement this differently. If you send red, and it looks blue + or green on the strip, modify this! It should be one of the values above + + + Example for TinyPICO: + + .. code-block:: python + + from dotstar import DotStar + from machine import Pin, SPI + + spi = SPI(sck=Pin(12), mosi=Pin(13), miso=Pin(18)) # Configure SPI - note: miso is unused + dotstar = DotStar(spi, 1) + dotstar[0] = (128, 0, 0) # Red + """ + + def __init__(self, spi, n, *, brightness=1.0, auto_write=True, pixel_order=BGR): + self._spi = spi + self._n = n + # Supply one extra clock cycle for each two pixels in the strip. + self.end_header_size = n // 16 + if n % 16 != 0: + self.end_header_size += 1 + self._buf = bytearray(n * 4 + START_HEADER_SIZE + self.end_header_size) + self.end_header_index = len(self._buf) - self.end_header_size + self.pixel_order = pixel_order + # Four empty bytes to start. + for i in range(START_HEADER_SIZE): + self._buf[i] = 0x00 + # Mark the beginnings of each pixel. + for i in range(START_HEADER_SIZE, self.end_header_index, 4): + self._buf[i] = 0xFF + # 0xff bytes at the end. + for i in range(self.end_header_index, len(self._buf)): + self._buf[i] = 0xFF + self._brightness = 1.0 + # Set auto_write to False temporarily so brightness setter does _not_ + # call show() while in __init__. + self.auto_write = False + self.brightness = brightness + self.auto_write = auto_write + + def deinit(self): + """Blank out the DotStars and release the resources.""" + self.auto_write = False + for i in range(START_HEADER_SIZE, self.end_header_index): + if i % 4 != 0: + self._buf[i] = 0 + self.show() + if self._spi: + self._spi.deinit() + + def __enter__(self): + return self + + def __exit__(self, exception_type, exception_value, traceback): + self.deinit() + + def __repr__(self): + return "[" + ", ".join([str(x) for x in self]) + "]" + + def _set_item(self, index, value): + """ + value can be one of three things: + a (r,g,b) list/tuple + a (r,g,b, brightness) list/tuple + a single, longer int that contains RGB values, like 0xFFFFFF + brightness, if specified should be a float 0-1 + + Set a pixel value. You can set per-pixel brightness here, if it's not passed it + will use the max value for pixel brightness value, which is a good default. + + Important notes about the per-pixel brightness - it's accomplished by + PWMing the entire output of the LED, and that PWM is at a much + slower clock than the rest of the LEDs. This can cause problems in + Persistence of Vision Applications + """ + + offset = index * 4 + START_HEADER_SIZE + rgb = value + if isinstance(value, int): + rgb = (value >> 16, (value >> 8) & 0xFF, value & 0xFF) + + if len(rgb) == 4: + brightness = value[3] + # Ignore value[3] below. + else: + brightness = 1 + + # LED startframe is three "1" bits, followed by 5 brightness bits + # then 8 bits for each of R, G, and B. The order of those 3 are configurable and + # vary based on hardware + # same as math.ceil(brightness * 31) & 0b00011111 + # Idea from https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions + brightness_byte = 32 - int(32 - brightness * 31) & 0b00011111 + self._buf[offset] = brightness_byte | LED_START + self._buf[offset + 1] = rgb[self.pixel_order[0]] + self._buf[offset + 2] = rgb[self.pixel_order[1]] + self._buf[offset + 3] = rgb[self.pixel_order[2]] + + def __setitem__(self, index, val): + if isinstance(index, slice): + start, stop, step = index.indices(self._n) + length = stop - start + if step != 0: + # same as math.ceil(length / step) + # Idea from https://fizzbuzzer.com/implement-a-ceil-function/ + length = (length + step - 1) // step + if len(val) != length: + raise ValueError("Slice and input sequence size do not match.") + for val_i, in_i in enumerate(range(start, stop, step)): + self._set_item(in_i, val[val_i]) + else: + self._set_item(index, val) + + if self.auto_write: + self.show() + + def __getitem__(self, index): + if isinstance(index, slice): + out = [] + for in_i in range(*index.indices(self._n)): + out.append(tuple(self._buf[in_i * 4 + (3 - i) + START_HEADER_SIZE] for i in range(3))) + return out + if index < 0: + index += len(self) + if index >= self._n or index < 0: + raise IndexError + offset = index * 4 + return tuple(self._buf[offset + (3 - i) + START_HEADER_SIZE] for i in range(3)) + + def __len__(self): + return self._n + + @property + def brightness(self): + """Overall brightness of the pixel""" + return self._brightness + + @brightness.setter + def brightness(self, brightness): + self._brightness = min(max(brightness, 0.0), 1.0) + if self.auto_write: + self.show() + + def fill(self, color): + """Colors all pixels the given ***color***.""" + auto_write = self.auto_write + self.auto_write = False + for i in range(self._n): + self[i] = color + if auto_write: + self.show() + self.auto_write = auto_write + + def show(self): + """Shows the new colors on the pixels themselves if they haven't already + been autowritten. + + The colors may or may not be showing after this function returns because + it may be done asynchronously.""" + # Create a second output buffer if we need to compute brightness + buf = self._buf + if self.brightness < 1.0: + buf = bytearray(self._buf) + # Four empty bytes to start. + for i in range(START_HEADER_SIZE): + buf[i] = 0x00 + for i in range(START_HEADER_SIZE, self.end_header_index): + buf[i] = self._buf[i] if i % 4 == 0 else int(self._buf[i] * self._brightness) + # Four 0xff bytes at the end. + for i in range(self.end_header_index, len(buf)): + buf[i] = 0xFF + + if self._spi: + self._spi.write(buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dotstar.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dotstar.pyi new file mode 100644 index 000000000..073e1ac20 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/dotstar.pyi @@ -0,0 +1,86 @@ +import types +from _typeshed import Incomplete + +START_HEADER_SIZE: int +LED_START: int +RGB: Incomplete +RBG: Incomplete +GRB: Incomplete +GBR: Incomplete +BRG: Incomplete +BGR: Incomplete + +class DotStar: + """ + A sequence of dotstars. + + :param SPI spi: The SPI object to write output to. + :param int n: The number of dotstars in the chain + :param float brightness: Brightness of the pixels between 0.0 and 1.0 + :param bool auto_write: True if the dotstars should immediately change when + set. If False, `show` must be called explicitly. + :param tuple pixel_order: Set the pixel order on the strip - different + strips implement this differently. If you send red, and it looks blue + or green on the strip, modify this! It should be one of the values above + + + Example for TinyPICO: + + .. code-block:: python + + from dotstar import DotStar + from machine import Pin, SPI + + spi = SPI(sck=Pin(12), mosi=Pin(13), miso=Pin(18)) # Configure SPI - note: miso is unused + dotstar = DotStar(spi, 1) + dotstar[0] = (128, 0, 0) # Red + """ + + _spi: Incomplete + _n: Incomplete + end_header_size: Incomplete + _buf: Incomplete + end_header_index: Incomplete + pixel_order: Incomplete + _brightness: float + auto_write: bool + def __init__(self, spi, n, *, brightness: float = 1.0, auto_write: bool = True, pixel_order=...) -> None: ... + def deinit(self) -> None: + """Blank out the DotStars and release the resources.""" + def __enter__(self): ... + def __exit__( + self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None + ) -> None: ... + def __repr__(self) -> str: ... + def _set_item(self, index, value) -> None: + """ + value can be one of three things: + a (r,g,b) list/tuple + a (r,g,b, brightness) list/tuple + a single, longer int that contains RGB values, like 0xFFFFFF + brightness, if specified should be a float 0-1 + + Set a pixel value. You can set per-pixel brightness here, if it's not passed it + will use the max value for pixel brightness value, which is a good default. + + Important notes about the per-pixel brightness - it's accomplished by + PWMing the entire output of the LED, and that PWM is at a much + slower clock than the rest of the LEDs. This can cause problems in + Persistence of Vision Applications + """ + def __setitem__(self, index, val) -> None: ... + def __getitem__(self, index): ... + def __len__(self) -> int: ... + @property + def brightness(self): + """Overall brightness of the pixel""" + @brightness.setter + def brightness(self, brightness) -> None: ... + def fill(self, color) -> None: + """Colors all pixels the given ***color***.""" + def show(self) -> None: + """Shows the new colors on the pixels themselves if they haven't already + been autowritten. + + The colors may or may not be showing after this function returns because + it may be done asynchronously.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/feathers2.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/feathers2.py new file mode 100644 index 000000000..9ec9967d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/feathers2.py @@ -0,0 +1,102 @@ +# FeatherS2 MicroPython Helper Library +# 2021 Seon Rozenblum - Unexpected Maker +# +# Project home: +# https://feathers2.io +# +# 2021-Mar-21 - v0.1 - Initial implementation + +# Import required libraries +from micropython import const +from machine import Pin, SPI, ADC +import machine, time + +# FeatherS2 Hardware Pin Assignments + +# LDO +LDO2 = 21 + +# APA102 Dotstar pins +DOTSTAR_CLK = 45 +DOTSTAR_DATA = 40 + +# SPI +SPI_MOSI = 35 +SPI_MISO = 37 +SPI_CLK = 36 + +# I2C +I2C_SDA = 8 +I2C_SCL = 9 + +# DAC +DAC1 = 17 +DAC2 = 18 + +# LED & Ambient Light Sensor +LED = 13 +AMB_LIGHT = 4 + +# Helper functions + + +# LED & Ambient Light Sensor control +def set_led(state): + l = Pin(LED, Pin.OUT) + l.value(state) + + +def toggle_led(state): + l = Pin(LED, Pin.OUT) + l.value(not l.value()) + + +# Create ADC and set attenuation and return the ambient light value from the onboard sensor +def get_amb_light(): + adc = ADC(Pin(AMB_LIGHT)) + adc.atten(ADC.ATTN_11DB) + return adc.read() + + +# LDO2 power control +# When we manually turn off the second LDO we also set the DotStar DATA and CLK pins to input to +# prevent parasitic power from lighting the LED even with the LDO off, causing current use. +# The DotStar is a beautiful LED, but parasitic power makes it a terrible choice for battery use :( +def set_ldo2_power(state): + """Set the power for the on-board Dotstar to allow no current draw when not needed.""" + # Set the power pin to the inverse of state + ldo2 = Pin(LDO2, Pin.OUT) + ldo2.value(state) + + if state: + Pin(DOTSTAR_CLK, Pin.OUT) + Pin(DOTSTAR_DATA, Pin.OUT) # If power is on, set CLK to be output, otherwise input + else: + Pin(DOTSTAR_CLK, Pin.IN) + Pin(DOTSTAR_DATA, Pin.IN) # If power is on, set CLK to be output, otherwise input + + # A small delay to let the IO change state + time.sleep(0.035) + + +# Dotstar rainbow colour wheel +def dotstar_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 + + +# Go into deep sleep but shut down the APA first to save power +# Use this if you want lowest deep sleep current +def go_deepsleep(t): + """Deep sleep helper that also powers down the on-board Dotstar.""" + set_ldo2_power(False) + machine.deepsleep(t) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/feathers2.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/feathers2.pyi new file mode 100644 index 000000000..4da0e326b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/feathers2.pyi @@ -0,0 +1,27 @@ +from machine import SPI as SPI +from micropython import const as const + +LDO2: int +DOTSTAR_CLK: int +DOTSTAR_DATA: int +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int +DAC1: int +DAC2: int +LED: int +AMB_LIGHT: int + +def set_led(state) -> None: ... +def toggle_led(state) -> None: ... +def get_amb_light(): ... +def set_ldo2_power(state) -> None: + """Set the power for the on-board Dotstar to allow no current draw when not needed.""" + +def dotstar_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + +def go_deepsleep(t) -> None: + """Deep sleep helper that also powers down the on-board Dotstar.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/modules.json new file mode 100644 index 000000000..e7ef05ad9 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/modules.json @@ -0,0 +1,116 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_FEATHERS2", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "dotstar.py", + "module": "dotstar" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "feathers2.py", + "module": "feathers2" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/feathers2neo.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/feathers2neo.py new file mode 100644 index 000000000..79f71e4aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/feathers2neo.py @@ -0,0 +1,91 @@ +# FeatherS2 Neo MicroPython Helper Library +# 2021 Seon Rozenblum - Unexpected Maker +# +# Project home: +# https://unexpectedmaker.com/feathers2-neo +# +# 2021-Sep-04 - v0.1 - Initial implementation + +# Import required libraries +from micropython import const +from machine import Pin, ADC +import machine + +# FeatherS2 Neo Hardware Pin Assignments + +# Sense Pins +VBUS_SENSE = 34 +VBAT_SENSE = 2 + +# RGB LED Pins +RGB_DATA = 40 +RGB_PWR = 39 + +# RGB MATRIX LED Pins +RGB_MATRIX_DATA = 21 +RGB_MATRIX_PWR = 4 + +# SPI +SPI_MOSI = 35 +SPI_MISO = 37 +SPI_CLK = 36 + +# I2C +I2C_SDA = 8 +I2C_SCL = 9 + +# DAC +DAC1 = 17 +DAC2 = 18 + + +# Helper functions +def set_pixel_power(state): + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + Pin(RGB_PWR, Pin.OUT).value(state) + + +def set_pixel_matrix_power(state): + """Enable or Disable power to the onboard NeoPixel RGB Matrix to either show colours, or to reduce power for deep sleep.""" + Pin(RGB_MATRIX_PWR, Pin.OUT).value(state) + + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + adc = ADC(Pin(VBAT_SENSE)) # Assign the ADC pin to read + measuredvbat = adc.read() # Read the value + measuredvbat /= 8192 # divide by 8192 as we are using the default ADC voltage range of 0-1V + measuredvbat *= 4.2 # Multiply by 4.2V, our reference voltage + return round(measuredvbat, 2) + + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + return Pin(VBUS_SENSE, Pin.IN).value() == 1 + + +# NeoPixel rainbow colour wheel +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 + + +# Go into deep sleep but shut down the RGB LED first to save power +# Use this if you want lowest deep sleep current +def go_deepsleep(t): + """Deep sleep helper that also powers down the on-board NeoPixel.""" + set_pixel_power(False) + set_pixel_matrix_power(False) + machine.deepsleep(t) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/feathers2neo.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/feathers2neo.pyi new file mode 100644 index 000000000..74ddc35cf --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/feathers2neo.pyi @@ -0,0 +1,36 @@ +from micropython import const as const + +VBUS_SENSE: int +VBAT_SENSE: int +RGB_DATA: int +RGB_PWR: int +RGB_MATRIX_DATA: int +RGB_MATRIX_PWR: int +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int +DAC1: int +DAC2: int + +def set_pixel_power(state) -> None: + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + +def set_pixel_matrix_power(state) -> None: + """Enable or Disable power to the onboard NeoPixel RGB Matrix to either show colours, or to reduce power for deep sleep.""" + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + +def go_deepsleep(t) -> None: + """Deep sleep helper that also powers down the on-board NeoPixel.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/modules.json new file mode 100644 index 000000000..d10479649 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_FEATHERS2NEO", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "feathers2neo.py", + "module": "feathers2neo" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS2NEO/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/feathers3.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/feathers3.py new file mode 100644 index 000000000..b9b9c873d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/feathers3.py @@ -0,0 +1,92 @@ +# FeatherS3 MicroPython Helper Library +# MIT license; Copyright (c) 2022 Seon Rozenblum - Unexpected Maker +# +# Project home: +# http://feathers3.io + +# Import required libraries +from micropython import const +from machine import Pin, ADC + +# FeatherS3 Hardware Pin Assignments + +# Sense Pins +VBUS_SENSE = 34 +VBAT_SENSE = 2 + +# RGB LED, LDO2 & Other Pins +RGB_DATA = 40 +LDO2 = 39 +LED = 13 +AMB_LIGHT = 4 + +# SPI +SPI_MOSI = 35 +SPI_MISO = 37 +SPI_CLK = 36 + +# I2C +I2C_SDA = 8 +I2C_SCL = 9 + +# Helper functions + + +# LED & Ambient Light Sensor control +def led_set(state): + """Set the state of the BLUE LED on IO13""" + l = Pin(LED, Pin.OUT) + l.value(state) + + +def led_blink(): + """Toggle the BLUE LED on IO13""" + l = Pin(LED, Pin.OUT) + l.value(not l.value()) + + +# Create ADC and set attenuation and return the ambient light value from the onboard sensor +def get_amb_light(): + """Get Ambient Light Sensor reading""" + adc = ADC(Pin(AMB_LIGHT)) + adc.atten(ADC.ATTN_11DB) + return adc.read() + + +def set_ldo2_power(state): + """Enable or Disable power to the second LDO""" + Pin(LDO2, Pin.OUT).value(state) + + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + adc = ADC(Pin(VBAT_SENSE)) # Assign the ADC pin to read + # Max voltage on ADC input will be 4.2V divided by R2 (442K) & R5 (160K), 4.2 / (160+442) * 160 = 1.1163V + adc.atten(ADC.ATTN_2_5DB) # Needs 2.5DB attenuation to read a max voltage of 1.1163V + # Use read_uv() to get ADC reading as this will use the on-chip calibration data + measuredvbat = adc.read_uv() / 1000000 # Read micovolts and convert to volts + measuredvbat *= 3.7624 # Multiply by ratio of battery voltage to ADC pin voltage: 4.2/1.1163 + return round(measuredvbat, 2) + + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + return Pin(VBUS_SENSE, Pin.IN).value() == 1 + + +# NeoPixel rainbow colour wheel +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/feathers3.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/feathers3.pyi new file mode 100644 index 000000000..ea2bd75d8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/feathers3.pyi @@ -0,0 +1,37 @@ +from micropython import const as const + +VBUS_SENSE: int +VBAT_SENSE: int +RGB_DATA: int +LDO2: int +LED: int +AMB_LIGHT: int +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int + +def led_set(state) -> None: + """Set the state of the BLUE LED on IO13""" + +def led_blink() -> None: + """Toggle the BLUE LED on IO13""" + +def get_amb_light(): + """Get Ambient Light Sensor reading""" + +def set_ldo2_power(state) -> None: + """Enable or Disable power to the second LDO""" + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/modules.json new file mode 100644 index 000000000..d4af3c0fa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_FEATHERS3", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "feathers3.py", + "module": "feathers3" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/feathers3neo.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/feathers3neo.py new file mode 100644 index 000000000..192bab3c7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/feathers3neo.py @@ -0,0 +1,103 @@ +# FeatherS3 Neo MicroPython Helper Library +# MIT license; Copyright (c) 2024 Seon Rozenblum - Unexpected Maker +# +# Project home: +# http://esp32s3.com + +# Import required libraries +from micropython import const +from machine import Pin, ADC + +# FeatherS3 Hardware Pin Assignments + +# Sense Pins +VBUS_SENSE = 15 +VBAT_SENSE = 2 + +# LDO2 & Other Pins +LDO2 = 39 +LED = 13 +AMB_LIGHT = 4 + +# RGB LED Pins +RGB_DATA = 40 +RGB_PWR = 39 + +# RGB MATRIX LED Pins +RGB_MATRIX_DATA = 16 +RGB_MATRIX_PWR = 39 + +# SPI +SPI_MOSI = 35 +SPI_MISO = 37 +SPI_CLK = 36 + +# I2C +I2C_SDA = 8 +I2C_SCL = 9 + +# Helper functions + + +# LED & Ambient Light Sensor control +def led_set(state): + """Set the state of the BLUE LED on IO13""" + l = Pin(LED, Pin.OUT) + l.value(state) + + +def led_blink(): + """Toggle the BLUE LED on IO13""" + l = Pin(LED, Pin.OUT) + l.value(not l.value()) + + +# Create ADC and set attenuation and return the ambient light value from the onboard sensor +def get_amb_light(): + """Get Ambient Light Sensor reading""" + adc = ADC(Pin(AMB_LIGHT)) + adc.atten(ADC.ATTN_11DB) + return adc.read() + + +def set_ldo2_power(state): + """ + Enable or Disable power to the second LDO, which is the LDO that powers the following items + RGB Matrix, RGB status LED, Ambient light Sensor. + This is ON by default and will automatically shut down when the ESP32 going into deep sleep. + """ + Pin(LDO2, Pin.OUT).value(state) + + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + adc = ADC(Pin(VBAT_SENSE)) # Assign the ADC pin to read + # Max voltage on ADC input will be 4.2V divided by R2 (442K) & R5 (160K), 4.2 / (160+442) * 160 = 1.1163V + adc.atten(ADC.ATTN_2_5DB) # Needs 2.5DB attenuation to read a max voltage of 1.1163V + # Use read_uv() to get ADC reading as this will use the on-chip calibration data + measuredvbat = adc.read_uv() / 1000000 # Read micovolts and convert to volts + measuredvbat *= 3.7624 # Multiply by ratio of battery voltage to ADC pin voltage: 4.2/1.1163 + return round(measuredvbat, 2) + + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + return Pin(VBUS_SENSE, Pin.IN).value() == 1 + + +# NeoPixel rainbow colour wheel +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/feathers3neo.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/feathers3neo.pyi new file mode 100644 index 000000000..add07e124 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/feathers3neo.pyi @@ -0,0 +1,44 @@ +from micropython import const as const + +VBUS_SENSE: int +VBAT_SENSE: int +LDO2: int +LED: int +AMB_LIGHT: int +RGB_DATA: int +RGB_PWR: int +RGB_MATRIX_DATA: int +RGB_MATRIX_PWR: int +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int + +def led_set(state) -> None: + """Set the state of the BLUE LED on IO13""" + +def led_blink() -> None: + """Toggle the BLUE LED on IO13""" + +def get_amb_light(): + """Get Ambient Light Sensor reading""" + +def set_ldo2_power(state) -> None: + """ + Enable or Disable power to the second LDO, which is the LDO that powers the following items + RGB Matrix, RGB status LED, Ambient light Sensor. + This is ON by default and will automatically shut down when the ESP32 going into deep sleep. + """ + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/modules.json new file mode 100644 index 000000000..2c15cd9c8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_FEATHERS3NEO", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "feathers3neo.py", + "module": "feathers3neo" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_FEATHERS3NEO/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/modules.json new file mode 100644 index 000000000..7d4549d61 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_NANOS3", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "nanos3.py", + "module": "nanos3" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/nanos3.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/nanos3.py new file mode 100644 index 000000000..4d2ebfea8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/nanos3.py @@ -0,0 +1,45 @@ +# NanoS3 Helper Library +# MIT license; Copyright (c) 2023 Seon Rozenblum - Unexpected Maker +# +# Project home: +# https://nanos3.io + +# Import required libraries +from micropython import const +from machine import Pin, ADC + +# TinyS3 Hardware Pin Assignments + +# RGB LED Pins +RGB_DATA = 41 +RGB_PWR = 42 + +# SPI +SPI_MOSI = 35 +SPI_MISO = 37 +SPI_CLK = 36 + +# I2C +I2C_SDA = 8 +I2C_SCL = 9 + + +# Helper functions +def set_pixel_power(state): + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + Pin(RGB_PWR, Pin.OUT).value(state) + + +# NeoPixel rainbow colour wheel +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/nanos3.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/nanos3.pyi new file mode 100644 index 000000000..a41f69292 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/nanos3.pyi @@ -0,0 +1,16 @@ +from machine import ADC as ADC +from micropython import const as const + +RGB_DATA: int +RGB_PWR: int +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int + +def set_pixel_power(state) -> None: + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_NANOS3/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/max17048.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/max17048.py new file mode 100644 index 000000000..538e55593 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/max17048.py @@ -0,0 +1,72 @@ +# Basic MAX17048 library for OMGS3 and other Unexpected Maker products +# MIT license; Copyright (c) 2024 Seon Rozenblum - Unexpected Maker +# +# Project home: +# https://unexpectedmaker.com + +from machine import I2C + + +class MAX17048: + _MAX17048_ADDRESS = 0x36 + + _VCELL_REGISTER = 0x02 + _SOC_REGISTER = 0x04 + _MODE_REGISTER = 0x06 + _VERSION_REGISTER = 0x08 + _HIBRT_REGISTER = 0x0A + _CONFIG_REGISTER = 0x0C + _COMMAND_REGISTER = 0xFE + + def __init__(self, i2c, address=_MAX17048_ADDRESS): + self.i2c = i2c + self.address = address + + def _read_register(self, register, num_bytes): + result = self.i2c.readfrom_mem(self.address, register, num_bytes) + return int.from_bytes(result, "big") + + def _write_register(self, register, value, num_bytes): + data = value.to_bytes(num_bytes, "big") + self.i2c.writeto_mem(self.address, register, data) + + @property + def cell_voltage(self): + """The voltage of the connected cell in Volts.""" + raw_voltage = self._read_register(self._VCELL_REGISTER, 2) + voltage = (raw_voltage >> 4) * 0.00125 + return voltage + + @property + def state_of_charge(self): + """The state of charge of the battery in percentage.""" + raw_soc = self._read_register(self._SOC_REGISTER, 2) + return raw_soc / 256 + + @property + def version(self): + """The chip version.""" + return self._read_register(self._VERSION_REGISTER, 2) + + @property + def hibernate(self): + """True if the chip is in hibernate mode, False otherwise.""" + hib = self._read_register(self._HIBRT_REGISTER, 2) + return (hib & 0x4000) != 0 + + @hibernate.setter + def hibernate(self, value): + config = self._read_register(self._CONFIG_REGISTER, 2) + if value: + config |= 0x8000 # Set the sleep bit + else: + config &= ~0x8000 # Clear the sleep bit + self._write_register(self._CONFIG_REGISTER, config, 2) + + def quick_start(self): + """Perform a quick start to reset the SOC calculation in the chip.""" + self._write_register(self._MODE_REGISTER, 0x4000, 2) + + def reset(self): + """Reset the chip.""" + self._write_register(self._COMMAND_REGISTER, 0x5400, 2) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/max17048.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/max17048.pyi new file mode 100644 index 000000000..81aaa168c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/max17048.pyi @@ -0,0 +1,35 @@ +from _typeshed import Incomplete +from machine import I2C as I2C + +class MAX17048: + _MAX17048_ADDRESS: int + _VCELL_REGISTER: int + _SOC_REGISTER: int + _MODE_REGISTER: int + _VERSION_REGISTER: int + _HIBRT_REGISTER: int + _CONFIG_REGISTER: int + _COMMAND_REGISTER: int + i2c: Incomplete + address: Incomplete + def __init__(self, i2c, address=...) -> None: ... + def _read_register(self, register, num_bytes): ... + def _write_register(self, register, value, num_bytes) -> None: ... + @property + def cell_voltage(self): + """The voltage of the connected cell in Volts.""" + @property + def state_of_charge(self): + """The state of charge of the battery in percentage.""" + @property + def version(self): + """The chip version.""" + @property + def hibernate(self): + """True if the chip is in hibernate mode, False otherwise.""" + @hibernate.setter + def hibernate(self, value) -> None: ... + def quick_start(self) -> None: + """Perform a quick start to reset the SOC calculation in the chip.""" + def reset(self) -> None: + """Reset the chip.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/modules.json new file mode 100644 index 000000000..3c441f175 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/modules.json @@ -0,0 +1,116 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_OMGS3", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "max17048.py", + "module": "max17048" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "omgs3.py", + "module": "omgs3" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/omgs3.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/omgs3.py new file mode 100644 index 000000000..b72b7f18b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/omgs3.py @@ -0,0 +1,56 @@ +# OMGS3 Helper Library +# MIT license; Copyright (c) 2024 Seon Rozenblum - Unexpected Maker +# +# Project home: +# https://omgs3.io + +# Import required libraries +from micropython import const +from machine import Pin, I2C +from max17048 import MAX17048 + +# Initialize I2C bus +fg_i2c = I2C(0, scl=Pin.board.I2C_SCL, sda=Pin.board.I2C_SDA) + +# Create an instance of the MAX17048 class +max17048 = MAX17048(fg_i2c) + + +# Helper functions +def get_bat_voltage(): + """Read the battery voltage from the fuel gauge""" + voltage = max17048.cell_voltage + print(f"Bat Voltage: {voltage}V") + return voltage + + +def get_state_of_charge(): + """Read the battery state of charge from the fuel gauge""" + soc = max17048.state_of_charge + print(f"State of Charge: {soc}%") + return soc + + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + return Pin(Pin.board.VBUS_SENSE, Pin.IN).value() == 1 + + +def set_pixel_power(state): + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + Pin(Pin.board.RGB_PWR, Pin.OUT).value(state) + + +# NeoPixel rainbow colour wheel +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/omgs3.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/omgs3.pyi new file mode 100644 index 000000000..1664ba540 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/omgs3.pyi @@ -0,0 +1,20 @@ +from _typeshed import Incomplete +from micropython import const as const + +fg_i2c: Incomplete +max17048: Incomplete + +def get_bat_voltage(): + """Read the battery voltage from the fuel gauge""" + +def get_state_of_charge(): + """Read the battery state of charge from the fuel gauge""" + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + +def set_pixel_power(state) -> None: + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_OMGS3/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/modules.json new file mode 100644 index 000000000..45b482cce --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_PROS3", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "pros3.py", + "module": "pros3" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/pros3.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/pros3.py new file mode 100644 index 000000000..aaf57a2dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/pros3.py @@ -0,0 +1,67 @@ +# ProS3 MicroPython Helper Library +# MIT license; Copyright (c) 2022 Seon Rozenblum - Unexpected Maker +# +# Project home: +# http://pros3.io + +# Import required libraries +from micropython import const +from machine import Pin, ADC + +# ProS3 Hardware Pin Assignments + +# Sense Pins +VBUS_SENSE = 33 +VBAT_SENSE = 10 + +# RGB LED & LDO2 Pins +RGB_DATA = 18 +LDO2 = 17 + +# SPI +SPI_MOSI = 35 +SPI_MISO = 37 +SPI_CLK = 36 + +# I2C +I2C_SDA = 8 +I2C_SCL = 9 + + +# Helper functions +def set_ldo2_power(state): + """Enable or Disable power to the second LDO""" + Pin(LDO2, Pin.OUT).value(state) + + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + adc = ADC(Pin(VBAT_SENSE)) # Assign the ADC pin to read + adc.atten(ADC.ATTN_2_5DB) # Needs 2.5DB attenuation for max voltage of 1.116V w/batt of 4.2V + measuredvbat = adc.read() + measuredvbat /= 3657 # Divide by 3657 as we are using 2.5dB attenuation, which is max input of 1.25V = 4095 counts + measuredvbat *= 4.2 # Multiply by 4.2V, our max charge voltage for a 1S LiPo + return round(measuredvbat, 2) + + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + return Pin(VBUS_SENSE, Pin.IN).value() == 1 + + +# NeoPixel rainbow colour wheel +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/pros3.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/pros3.pyi new file mode 100644 index 000000000..4787c5a0f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/pros3.pyi @@ -0,0 +1,26 @@ +from micropython import const as const + +VBUS_SENSE: int +VBAT_SENSE: int +RGB_DATA: int +LDO2: int +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int + +def set_ldo2_power(state) -> None: + """Enable or Disable power to the second LDO""" + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_PROS3/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/modules.json new file mode 100644 index 000000000..831341386 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/modules.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_RGBTOUCH_MINI", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_RGBTOUCH_MINI/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dotstar.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dotstar.py new file mode 100644 index 000000000..b16d1cde1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dotstar.py @@ -0,0 +1,225 @@ +# DotStar strip driver for MicroPython +# +# The MIT License (MIT) +# +# Copyright (c) 2016 Damien P. George (original Neopixel object) +# Copyright (c) 2017 Ladyada +# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries +# Copyright (c) 2019 Matt Trentini (porting back to MicroPython) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +START_HEADER_SIZE = 4 +LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits + +# Pixel color order constants +RGB = (0, 1, 2) +RBG = (0, 2, 1) +GRB = (1, 0, 2) +GBR = (1, 2, 0) +BRG = (2, 0, 1) +BGR = (2, 1, 0) + + +class DotStar: + """ + A sequence of dotstars. + + :param SPI spi: The SPI object to write output to. + :param int n: The number of dotstars in the chain + :param float brightness: Brightness of the pixels between 0.0 and 1.0 + :param bool auto_write: True if the dotstars should immediately change when + set. If False, `show` must be called explicitly. + :param tuple pixel_order: Set the pixel order on the strip - different + strips implement this differently. If you send red, and it looks blue + or green on the strip, modify this! It should be one of the values above + + + Example for TinyPICO: + + .. code-block:: python + + from dotstar import DotStar + from machine import Pin, SPI + + spi = SPI(sck=Pin(12), mosi=Pin(13), miso=Pin(18)) # Configure SPI - note: miso is unused + dotstar = DotStar(spi, 1) + dotstar[0] = (128, 0, 0) # Red + """ + + def __init__(self, spi, n, *, brightness=1.0, auto_write=True, pixel_order=BGR): + self._spi = spi + self._n = n + # Supply one extra clock cycle for each two pixels in the strip. + self.end_header_size = n // 16 + if n % 16 != 0: + self.end_header_size += 1 + self._buf = bytearray(n * 4 + START_HEADER_SIZE + self.end_header_size) + self.end_header_index = len(self._buf) - self.end_header_size + self.pixel_order = pixel_order + # Four empty bytes to start. + for i in range(START_HEADER_SIZE): + self._buf[i] = 0x00 + # Mark the beginnings of each pixel. + for i in range(START_HEADER_SIZE, self.end_header_index, 4): + self._buf[i] = 0xFF + # 0xff bytes at the end. + for i in range(self.end_header_index, len(self._buf)): + self._buf[i] = 0xFF + self._brightness = 1.0 + # Set auto_write to False temporarily so brightness setter does _not_ + # call show() while in __init__. + self.auto_write = False + self.brightness = brightness + self.auto_write = auto_write + + def deinit(self): + """Blank out the DotStars and release the resources.""" + self.auto_write = False + for i in range(START_HEADER_SIZE, self.end_header_index): + if i % 4 != 0: + self._buf[i] = 0 + self.show() + if self._spi: + self._spi.deinit() + + def __enter__(self): + return self + + def __exit__(self, exception_type, exception_value, traceback): + self.deinit() + + def __repr__(self): + return "[" + ", ".join([str(x) for x in self]) + "]" + + def _set_item(self, index, value): + """ + value can be one of three things: + a (r,g,b) list/tuple + a (r,g,b, brightness) list/tuple + a single, longer int that contains RGB values, like 0xFFFFFF + brightness, if specified should be a float 0-1 + + Set a pixel value. You can set per-pixel brightness here, if it's not passed it + will use the max value for pixel brightness value, which is a good default. + + Important notes about the per-pixel brightness - it's accomplished by + PWMing the entire output of the LED, and that PWM is at a much + slower clock than the rest of the LEDs. This can cause problems in + Persistence of Vision Applications + """ + + offset = index * 4 + START_HEADER_SIZE + rgb = value + if isinstance(value, int): + rgb = (value >> 16, (value >> 8) & 0xFF, value & 0xFF) + + if len(rgb) == 4: + brightness = value[3] + # Ignore value[3] below. + else: + brightness = 1 + + # LED startframe is three "1" bits, followed by 5 brightness bits + # then 8 bits for each of R, G, and B. The order of those 3 are configurable and + # vary based on hardware + # same as math.ceil(brightness * 31) & 0b00011111 + # Idea from https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions + brightness_byte = 32 - int(32 - brightness * 31) & 0b00011111 + self._buf[offset] = brightness_byte | LED_START + self._buf[offset + 1] = rgb[self.pixel_order[0]] + self._buf[offset + 2] = rgb[self.pixel_order[1]] + self._buf[offset + 3] = rgb[self.pixel_order[2]] + + def __setitem__(self, index, val): + if isinstance(index, slice): + start, stop, step = index.indices(self._n) + length = stop - start + if step != 0: + # same as math.ceil(length / step) + # Idea from https://fizzbuzzer.com/implement-a-ceil-function/ + length = (length + step - 1) // step + if len(val) != length: + raise ValueError("Slice and input sequence size do not match.") + for val_i, in_i in enumerate(range(start, stop, step)): + self._set_item(in_i, val[val_i]) + else: + self._set_item(index, val) + + if self.auto_write: + self.show() + + def __getitem__(self, index): + if isinstance(index, slice): + out = [] + for in_i in range(*index.indices(self._n)): + out.append(tuple(self._buf[in_i * 4 + (3 - i) + START_HEADER_SIZE] for i in range(3))) + return out + if index < 0: + index += len(self) + if index >= self._n or index < 0: + raise IndexError + offset = index * 4 + return tuple(self._buf[offset + (3 - i) + START_HEADER_SIZE] for i in range(3)) + + def __len__(self): + return self._n + + @property + def brightness(self): + """Overall brightness of the pixel""" + return self._brightness + + @brightness.setter + def brightness(self, brightness): + self._brightness = min(max(brightness, 0.0), 1.0) + if self.auto_write: + self.show() + + def fill(self, color): + """Colors all pixels the given ***color***.""" + auto_write = self.auto_write + self.auto_write = False + for i in range(self._n): + self[i] = color + if auto_write: + self.show() + self.auto_write = auto_write + + def show(self): + """Shows the new colors on the pixels themselves if they haven't already + been autowritten. + + The colors may or may not be showing after this function returns because + it may be done asynchronously.""" + # Create a second output buffer if we need to compute brightness + buf = self._buf + if self.brightness < 1.0: + buf = bytearray(self._buf) + # Four empty bytes to start. + for i in range(START_HEADER_SIZE): + buf[i] = 0x00 + for i in range(START_HEADER_SIZE, self.end_header_index): + buf[i] = self._buf[i] if i % 4 == 0 else int(self._buf[i] * self._brightness) + # Four 0xff bytes at the end. + for i in range(self.end_header_index, len(buf)): + buf[i] = 0xFF + + if self._spi: + self._spi.write(buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dotstar.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dotstar.pyi new file mode 100644 index 000000000..073e1ac20 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/dotstar.pyi @@ -0,0 +1,86 @@ +import types +from _typeshed import Incomplete + +START_HEADER_SIZE: int +LED_START: int +RGB: Incomplete +RBG: Incomplete +GRB: Incomplete +GBR: Incomplete +BRG: Incomplete +BGR: Incomplete + +class DotStar: + """ + A sequence of dotstars. + + :param SPI spi: The SPI object to write output to. + :param int n: The number of dotstars in the chain + :param float brightness: Brightness of the pixels between 0.0 and 1.0 + :param bool auto_write: True if the dotstars should immediately change when + set. If False, `show` must be called explicitly. + :param tuple pixel_order: Set the pixel order on the strip - different + strips implement this differently. If you send red, and it looks blue + or green on the strip, modify this! It should be one of the values above + + + Example for TinyPICO: + + .. code-block:: python + + from dotstar import DotStar + from machine import Pin, SPI + + spi = SPI(sck=Pin(12), mosi=Pin(13), miso=Pin(18)) # Configure SPI - note: miso is unused + dotstar = DotStar(spi, 1) + dotstar[0] = (128, 0, 0) # Red + """ + + _spi: Incomplete + _n: Incomplete + end_header_size: Incomplete + _buf: Incomplete + end_header_index: Incomplete + pixel_order: Incomplete + _brightness: float + auto_write: bool + def __init__(self, spi, n, *, brightness: float = 1.0, auto_write: bool = True, pixel_order=...) -> None: ... + def deinit(self) -> None: + """Blank out the DotStars and release the resources.""" + def __enter__(self): ... + def __exit__( + self, exception_type: type[BaseException] | None, exception_value: BaseException | None, traceback: types.TracebackType | None + ) -> None: ... + def __repr__(self) -> str: ... + def _set_item(self, index, value) -> None: + """ + value can be one of three things: + a (r,g,b) list/tuple + a (r,g,b, brightness) list/tuple + a single, longer int that contains RGB values, like 0xFFFFFF + brightness, if specified should be a float 0-1 + + Set a pixel value. You can set per-pixel brightness here, if it's not passed it + will use the max value for pixel brightness value, which is a good default. + + Important notes about the per-pixel brightness - it's accomplished by + PWMing the entire output of the LED, and that PWM is at a much + slower clock than the rest of the LEDs. This can cause problems in + Persistence of Vision Applications + """ + def __setitem__(self, index, val) -> None: ... + def __getitem__(self, index): ... + def __len__(self) -> int: ... + @property + def brightness(self): + """Overall brightness of the pixel""" + @brightness.setter + def brightness(self, brightness) -> None: ... + def fill(self, color) -> None: + """Colors all pixels the given ***color***.""" + def show(self) -> None: + """Shows the new colors on the pixels themselves if they haven't already + been autowritten. + + The colors may or may not be showing after this function returns because + it may be done asynchronously.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/modules.json new file mode 100644 index 000000000..09e53130a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/modules.json @@ -0,0 +1,116 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_TINYPICO", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "dotstar.py", + "module": "dotstar" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "tinypico.py", + "module": "tinypico" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/tinypico.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/tinypico.py new file mode 100644 index 000000000..727599414 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/tinypico.py @@ -0,0 +1,118 @@ +# TinyPICO MicroPython Helper Library +# 2019 Seon Rozenblum, Matt Trentini +# +# Project home: +# https://github.com/TinyPICO +# +# 2019-Mar-12 - v0.1 - Initial implementation +# 2019-May-20 - v1.0 - Initial Release +# 2019-Oct-23 - v1.1 - Removed temp sensor code, prep for frozen modules + +# Import required libraries +from micropython import const +from machine import Pin, SPI, ADC +import machine +import time +import esp32 + +# TinyPICO Hardware Pin Assignments + +# Battery +BAT_VOLTAGE = 35 +BAT_CHARGE = 34 + +# APA102 Dotstar pins for production boards +DOTSTAR_CLK = 12 +DOTSTAR_DATA = 2 +DOTSTAR_PWR = 13 + +# SPI +SPI_MOSI = 23 +SPI_CLK = 18 +SPI_MISO = 19 + +# I2C +I2C_SDA = 21 +I2C_SCL = 22 + +# DAC +DAC1 = 25 +DAC2 = 26 + +# Helper functions + + +# Get a *rough* estimate of the current battery voltage +# If the battery is not present, the charge IC will still report it's trying to charge at X voltage +# so it will still show a voltage. +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 3.7V + This is an approximation only, but useful to detect of the charge state of the battery is getting low. + """ + adc = ADC(Pin(BAT_VOLTAGE)) # Assign the ADC pin to read + measuredvbat = adc.read() # Read the value + measuredvbat /= 4095 # divide by 4095 as we are using the default ADC voltage range of 0-1V + measuredvbat *= 3.7 # Multiply by 3.7V, our reference voltage + return measuredvbat + + +# Return the current charge state of the battery - we need to read the value multiple times +# to eliminate false negatives due to the charge IC not knowing the difference between no battery +# and a full battery not charging - This is why the charge LED flashes +def get_battery_charging(): + """ + Returns the current battery charging state. + This can trigger false positives as the charge IC can't tell the difference between a full battery or no battery connected. + """ + measuredVal = 0 # start our reading at 0 + io = Pin(BAT_CHARGE, Pin.IN) # Assign the pin to read + + for y in range(0, 10): # loop through 10 times adding the read values together to ensure no false positives + measuredVal += io.value() + + return measuredVal == 0 # return True if the value is 0 + + +# Power to the on-board Dotstar is controlled by a PNP transistor, so low is ON and high is OFF +# We also need to set the Dotstar clock and data pins to be inputs to prevent power leakage when power is off +# This might be improved at a future date +# The reason we have power control for the Dotstar is that it has a quiescent current of around 1mA, so we +# need to be able to cut power to it to minimise power consumption during deep sleep or with general battery powered use +# to minimise unneeded battery drain +def set_dotstar_power(state): + """Set the power for the on-board Dotstar to allow no current draw when not needed.""" + # Set the power pin to the inverse of state + if state: + Pin(DOTSTAR_PWR, Pin.OUT, None, value=0) # Drive output to LOW to enable transistor + else: + Pin(DOTSTAR_PWR, Pin.IN, None) # Disable output, external pull-up will disable transistor + + Pin(DOTSTAR_CLK, Pin.OUT if state else Pin.IN) # If power is on, set CLK to be output, otherwise input + Pin(DOTSTAR_DATA, Pin.OUT if state else Pin.IN) # If power is on, set DATA to be output, otherwise input + + # A small delay to let the IO change state + time.sleep(0.035) + + +# Dotstar rainbow colour wheel +def dotstar_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 + + +# Go into deep sleep but shut down the APA first to save power +# Use this if you want lowest deep sleep current +def go_deepsleep(t): + """Deep sleep helper that also powers down the on-board Dotstar.""" + set_dotstar_power(False) + machine.deepsleep(t) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/tinypico.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/tinypico.pyi new file mode 100644 index 000000000..adfa1c09e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/tinypico.pyi @@ -0,0 +1,36 @@ +from machine import SPI as SPI +from micropython import const as const + +BAT_VOLTAGE: int +BAT_CHARGE: int +DOTSTAR_CLK: int +DOTSTAR_DATA: int +DOTSTAR_PWR: int +SPI_MOSI: int +SPI_CLK: int +SPI_MISO: int +I2C_SDA: int +I2C_SCL: int +DAC1: int +DAC2: int + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 3.7V + This is an approximation only, but useful to detect of the charge state of the battery is getting low. + """ + +def get_battery_charging(): + """ + Returns the current battery charging state. + This can trigger false positives as the charge IC can't tell the difference between a full battery or no battery connected. + """ + +def set_dotstar_power(state) -> None: + """Set the power for the on-board Dotstar to allow no current draw when not needed.""" + +def dotstar_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + +def go_deepsleep(t) -> None: + """Deep sleep helper that also powers down the on-board Dotstar.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYPICO/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/modules.json new file mode 100644 index 000000000..56a99f2f5 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_TINYS2", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "tinys2.py", + "module": "tinys2" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/tinys2.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/tinys2.py new file mode 100644 index 000000000..4a522d993 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/tinys2.py @@ -0,0 +1,82 @@ +# TinyS2 MicroPython Helper Library +# 2021 Seon Rozenblum - Unexpected Maker +# +# Project home: +# https://tinys2.io +# +# 2021-Apr-10 - v0.1 - Initial implementation + +# Import required libraries +from micropython import const +from machine import Pin, SPI, ADC +import machine + +# TinyS2 Hardware Pin Assignments + +# Sense Pins +VBUS_SENSE = 21 +VBAT_SENSE = 3 + + +# RGB LED Pins +RGB_DATA = 1 +RGB_PWR = 2 + +# SPI +SPI_MOSI = 35 +SPI_MISO = 36 +SPI_CLK = 37 + +# I2C +I2C_SDA = 8 +I2C_SCL = 9 + +# DAC +DAC1 = 17 +DAC2 = 18 + + +# Helper functions +def set_pixel_power(state): + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + Pin(RGB_PWR, Pin.OUT).value(state) + + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + adc = ADC(Pin(VBAT_SENSE)) # Assign the ADC pin to read + measuredvbat = adc.read() # Read the value + measuredvbat /= 8192 # divide by 8192 as we are using the default ADC voltage range of 0-1V + measuredvbat *= 4.2 # Multiply by 4.2V, our reference voltage + return round(measuredvbat, 2) + + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + return Pin(VBUS_SENSE, Pin.IN).value() == 1 + + +# NeoPixel rainbow colour wheel +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 + + +# Go into deep sleep but shut down the RGB LED first to save power +# Use this if you want lowest deep sleep current +def go_deepsleep(t): + """Deep sleep helper that also powers down the on-board NeoPixel.""" + set_pixel_power(False) + machine.deepsleep(t) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/tinys2.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/tinys2.pyi new file mode 100644 index 000000000..927820d4b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/tinys2.pyi @@ -0,0 +1,32 @@ +from machine import SPI as SPI +from micropython import const as const + +VBUS_SENSE: int +VBAT_SENSE: int +RGB_DATA: int +RGB_PWR: int +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int +DAC1: int +DAC2: int + +def set_pixel_power(state) -> None: + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + +def go_deepsleep(t) -> None: + """Deep sleep helper that also powers down the on-board NeoPixel.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS2/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/_boot.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/_boot.py new file mode 100644 index 000000000..96af581f3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/_boot.py @@ -0,0 +1,13 @@ +import gc +import vfs +from flashbdev import bdev + +try: + if bdev: + vfs.mount(bdev, "/") +except OSError: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/aioespnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/aioespnow.py new file mode 100644 index 000000000..dec925de2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/aioespnow.py @@ -0,0 +1,31 @@ +# aioespnow module for MicroPython on ESP32 and ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +import asyncio +import espnow + + +# Modelled on the asyncio.Stream class (extmod/asyncio/stream.py) +# NOTE: Relies on internal implementation of asyncio.core (_io_queue) +class AIOESPNow(espnow.ESPNow): + # Read one ESPNow message + async def arecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.recv(0) # type: ignore[misc] + + async def airecv(self): + yield asyncio.core._io_queue.queue_read(self) + return self.irecv(0) # type: ignore[misc] + + async def asend(self, mac, msg=None, sync=None): + if msg is None: + msg, mac = mac, None # If msg is None: swap mac and msg + yield asyncio.core._io_queue.queue_write(self) + return self.send(mac, msg, sync) # type: ignore[misc] + + # "async for" support + def __aiter__(self): + return self + + async def __anext__(self): + return await self.airecv() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/aioespnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/aioespnow.pyi new file mode 100644 index 000000000..e58cfc873 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/aioespnow.pyi @@ -0,0 +1,10 @@ +import espnow +from _typeshed import Incomplete +from collections.abc import Generator + +class AIOESPNow(espnow.ESPNow): + async def arecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def airecv(self) -> Generator[Incomplete, None, Incomplete]: ... + async def asend(self, mac, msg=None, sync=None) -> Generator[Incomplete, None, Incomplete]: ... + def __aiter__(self): ... + async def __anext__(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/apa106.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/apa106.py new file mode 100644 index 000000000..ef971d78b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/apa106.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/apa106.pyi new file mode 100644 index 000000000..5f193d6e1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/apa106.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA106(NeoPixel): + ORDER: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/dht.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/espnow.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/espnow.py new file mode 100644 index 000000000..6956a3a93 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/espnow.py @@ -0,0 +1,30 @@ +# espnow module for MicroPython on ESP32 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [None, bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def irq(self, callback): + super().irq(callback, self) + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/espnow.pyi new file mode 100644 index 000000000..64beaa397 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/espnow.pyi @@ -0,0 +1,294 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + def irq(self, callback) -> None: + """ + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/flashbdev.py new file mode 100644 index 000000000..1ee6ff779 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/flashbdev.py @@ -0,0 +1,7 @@ +from esp32 import Partition + +# MicroPython's partition table uses "vfs", TinyUF2 uses "ffat". +bdev = Partition.find(Partition.TYPE_DATA, label="vfs") +if not bdev: + bdev = Partition.find(Partition.TYPE_DATA, label="ffat", block_size=512) +bdev = bdev[0] if bdev else None diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/flashbdev.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/flashbdev.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/inisetup.py new file mode 100644 index 000000000..4e9b462fb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/inisetup.py @@ -0,0 +1,57 @@ +import vfs +from flashbdev import bdev + + +def check_bootsec(): + buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""" + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + if bdev.info()[4] == "vfs": + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + elif bdev.info()[4] == "ffat": + vfs.VfsFat.mkfs(bdev) + fs = vfs.VfsFat(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""" + ) + return fs diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/inisetup.pyi new file mode 100644 index 000000000..d6ea7f830 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/inisetup.pyi @@ -0,0 +1,3 @@ +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/machine.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/machine.py new file mode 100644 index 000000000..04754c3d0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/machine.py @@ -0,0 +1,192 @@ +import sys + +_path = sys.path +sys.path = () +try: + import machine as _machine +finally: + sys.path = _path + del _path + del sys + + +from micropython import const +import esp32 + +if hasattr(esp32, "PCNT"): + _PCNT_RANGE = 32000 + + class _CounterBase: + _PCNT = esp32.PCNT + # Singletons, keyed by PCNT unit_id (shared by both Counter & Encoder). + _INSTANCES = {} + + # Use __new__ to implement a singleton rather than a factory function, + # because we need to be able to provide class attributes, e.g. + # Counter.RISING, which is not possible if Counter was a function + # (functions cannot have attributes in MicroPython). + def __new__(cls, unit_id, *_args, **_kwargs): + # Find an existing instance for this PCNT unit id. + self = cls._INSTANCES.get(unit_id) + + if self: + # Verify that this PCNT is being used for the same type + # (Encoder or Counter). + if not isinstance(self, cls): + raise ValueError("PCNT in use") + else: + # Previously unused PCNT unit. + self = object.__new__(cls) + cls._INSTANCES[unit_id] = self + + # __init__ will now be called with the same args. + return self + + def __init__(self, unit_id, *args, filter_ns=0, **kwargs): + self._unit_id = unit_id + + if not hasattr(self, "_pcnt"): + # New instance, or previously deinit-ed. + self._pcnt = self._PCNT(unit_id, min=-_PCNT_RANGE, max=_PCNT_RANGE) + elif not (args or kwargs): + # Existing instance, and no args, so accessing the existing + # singleton without reconfiguring. Note: This means that + # Counter/Encoder cannot be partially re-initalised. Either + # you get the existing instance as-is (by passing no arguments + # other than the id), or you must pass all the necessary + # arguments to additionally re-configure it. + return + + # Counter- or Encoder-specific configuration of self._pcnt. + self._configure(*args, **kwargs) + + # Common unit configuration. + self._pcnt.init( + filter=min(max(0, filter_ns * 80 // 1000), 1023), + value=0, + ) + + # Note: We track number-of-overflows rather than the actual count in + # order to avoid the IRQ handler overflowing MicroPython's "small int" + # range. This gives an effective range of 2**30 overflows. User code + # should use counter.value(0) to reset the overflow count. + # The ESP32 PCNT resets to zero on under/overflow (i.e. it does not wrap + # around to the opposite limit), so each overflow corresponds to exactly + # _PCNT_RANGE counts. + + # Reset counter state. + self._overflows = 0 + self._offset = 0 + + # Install IRQ handler to handle under/overflow. + self._pcnt.irq(self._overflow, self._PCNT.IRQ_MIN | self._PCNT.IRQ_MAX) + + # Start counting. + self._pcnt.start() + + # Handle counter under/overflow. + def _overflow(self, pcnt): + mask = pcnt.irq().flags() + if mask & self._PCNT.IRQ_MIN: + self._overflows -= 1 + elif mask & self._PCNT.IRQ_MAX: + self._overflows += 1 + + # Public machine.Counter & machine.Encoder API. + def init(self, *args, **kwargs): + self.__init__(self._unit_id, *args, **kwargs) + + # Public machine.Counter & machine.Encoder API. + def deinit(self): + if hasattr(self, "_pcnt"): + self._pcnt.deinit() + del self._pcnt + + # Public machine.Counter & machine.Encoder API. + def value(self, value=None): + if not hasattr(self, "_pcnt"): + raise RuntimeError("not initialised") + + # This loop deals with the possibility that a PCNT overflow occurs + # between retrieving self._overflows and self._pcnt.value(). + while True: + overflows = self._overflows + current = self._pcnt.value() + # Calling PCNT.value() forces any pending interrupts to run + # for this PCNT unit. So self._overflows must now be the the + # value corresponding to the value we read. + if self._overflows == overflows: + break + + # Compute the result including the number of times we've cycled + # through the range, and any applied offset. + result = overflows * _PCNT_RANGE + current + self._offset + + # If a new value is specified, then zero out the overflows, and set + # self._offset so that it zeros out the current PCNT value. The + # mutation to self._overflows is atomic w.r.t. the overflow IRQ + # handler because the scheduler only runs on branch instructions. + if value is not None: + self._overflows -= overflows + self._offset = value - current + + return result + + class Counter(_CounterBase): + # Public machine.Counter API. + RISING = 1 + FALLING = 2 + UP = _CounterBase._PCNT.INCREMENT + DOWN = _CounterBase._PCNT.DECREMENT + + # Counter-specific configuration. + def _configure(self, src, edge=RISING, direction=UP): + # Only use the first channel. + self._pcnt.init( + channel=0, + pin=src, + rising=direction if edge & Counter.RISING else self._PCNT.IGNORE, + falling=direction if edge & Counter.FALLING else self._PCNT.IGNORE, + ) + + class Encoder(_CounterBase): + # Encoder-specific configuration. + def _configure(self, phase_a, phase_b, phases=1): + if phases not in (1, 2, 4): + raise ValueError("phases") + # Configure the first channel. + self._pcnt.init( + channel=0, + pin=phase_a, + falling=self._PCNT.INCREMENT, + rising=self._PCNT.DECREMENT, + mode_pin=phase_b, + mode_low=self._PCNT.HOLD if phases == 1 else self._PCNT.REVERSE, + ) + if phases == 4: + # For 4x quadrature, enable the second channel. + self._pcnt.init( + channel=1, + pin=phase_b, + falling=self._PCNT.DECREMENT, + rising=self._PCNT.INCREMENT, + mode_pin=phase_a, + mode_low=self._PCNT.REVERSE, + ) + else: + # For 1x and 2x quadrature, disable the second channel. + self._pcnt.init(channel=1, pin=None, rising=self._PCNT.IGNORE) + self._phases = phases + + def phases(self): + return self._phases + + del _CounterBase + + +del esp32 + + +# Delegate to built-in machine module. +def __getattr__(attr): + return getattr(_machine, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/machine.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/machine.pyi new file mode 100644 index 000000000..da1d31b14 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/machine.pyi @@ -0,0 +1,1522 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from micropython import const as const +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from typing import NoReturn, Callable, Any, overload +from vfs import AbstractBlockDev + +_path: Incomplete +_PCNT_RANGE: int +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +PWRON_RESET: Incomplete +"""Reset causes.""" +HARD_RESET: Incomplete +"""Reset causes.""" +WDT_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +SOFT_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +class _CounterBase: + _PCNT: Incomplete + _INSTANCES: Incomplete + def __new__(cls, unit_id, *_args, **_kwargs): ... + _unit_id: Incomplete + _pcnt: Incomplete + _overflows: int + _offset: int + def __init__(self, unit_id, *args, filter_ns: int = 0, **kwargs) -> None: ... + def _overflow(self, pcnt) -> None: ... + def init(self, *args, **kwargs) -> None: ... + def deinit(self) -> None: ... + def value(self, value=None): ... + +class Counter: + """ + Returns the singleton Counter object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Counter instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + RISING: int + """Select the pulse edge.""" + FALLING: int + """Select the pulse edge.""" + UP: Incomplete + """Select the counting direction.""" + DOWN: Incomplete + """Select the counting direction.""" + def _configure(self, src, edge=..., direction=...) -> None: ... + +class Encoder: + """ + Returns the singleton Encoder object for the the given *id*. Values of *id* + depend on a particular port and its hardware. Values 0, 1, etc. are commonly + used to select hardware block #0, #1, etc. + + Additional arguments are passed to the :meth:`init` method described below, + and will cause the Encoder instance to be re-initialised and reset. + + On ESP32, the *id* corresponds to a :ref:`PCNT unit `. + """ + + _phases: Incomplete + def _configure(self, phase_a, phase_b, phases: int = 1) -> None: ... + def phases(self): ... + +def __getattr__(attr): ... + +class ADC: + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... + +class I2C: + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class Pin: + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class PWM: + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + +class RTC: + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + +class SDCard: + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + +class Signal: + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + +class SPI: + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + +class Timer: + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + +class UART: + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/modules.json b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/modules.json new file mode 100644 index 000000000..8aac35fc3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp32", + "platform": "esp32", + "machine": "UM_TINYS3", + "firmware": "micropython-esp32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "aioespnow.py", + "module": "aioespnow" + }, + { + "file": "apa106.py", + "module": "apa106" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "machine.py", + "module": "machine" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "tinys3.py", + "module": "tinys3" + }, + { + "file": "umqtt/__init__.py", + "module": "__init__" + }, + { + "file": "umqtt/robust.py", + "module": "robust" + }, + { + "file": "umqtt/simple.py", + "module": "simple" + }, + { + "file": "upysh.py", + "module": "upysh" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/onewire.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/removed.txt b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ssl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/tinys3.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/tinys3.py new file mode 100644 index 000000000..3cc72d23d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/tinys3.py @@ -0,0 +1,67 @@ +# TinyS3 Helper Library +# MIT license; Copyright (c) 2022 Seon Rozenblum - Unexpected Maker +# +# Project home: +# https://tinys3.io + +# Import required libraries +from micropython import const +from machine import Pin, ADC + +# TinyS3 Hardware Pin Assignments + +# Sense Pins +VBUS_SENSE = 33 +VBAT_SENSE = 10 + +# RGB LED Pins +RGB_DATA = 18 +RGB_PWR = 17 + +# SPI +SPI_MOSI = 35 +SPI_MISO = 37 +SPI_CLK = 36 + +# I2C +I2C_SDA = 8 +I2C_SCL = 9 + + +# Helper functions +def set_pixel_power(state): + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + Pin(RGB_PWR, Pin.OUT).value(state) + + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + adc = ADC(Pin(VBAT_SENSE)) # Assign the ADC pin to read + adc.atten(ADC.ATTN_2_5DB) # Needs 2.5DB attenuation for max voltage of 1.116V w/batt of 4.2V + measuredvbat = adc.read() + measuredvbat /= 3657 # Divide by 3657 as we are using 2.5dB attenuation, which is max input of 1.25V = 4095 counts + measuredvbat *= 4.2 # Multiply by 4.2V, our max charge voltage for a 1S LiPo + return round(measuredvbat, 2) + + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + return Pin(VBUS_SENSE, Pin.IN).value() == 1 + + +# NeoPixel rainbow colour wheel +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" + wheel_pos = wheel_pos % 255 + + if wheel_pos < 85: + return 255 - wheel_pos * 3, 0, wheel_pos * 3 + elif wheel_pos < 170: + wheel_pos -= 85 + return 0, wheel_pos * 3, 255 - wheel_pos * 3 + else: + wheel_pos -= 170 + return wheel_pos * 3, 255 - wheel_pos * 3, 0 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/tinys3.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/tinys3.pyi new file mode 100644 index 000000000..81a0e1428 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/tinys3.pyi @@ -0,0 +1,26 @@ +from micropython import const as const + +VBUS_SENSE: int +VBAT_SENSE: int +RGB_DATA: int +RGB_PWR: int +SPI_MOSI: int +SPI_MISO: int +SPI_CLK: int +I2C_SDA: int +I2C_SCL: int + +def set_pixel_power(state) -> None: + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + +def rgb_color_wheel(wheel_pos): + """Color wheel to allow for cycling through the rainbow of RGB colors.""" diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/__init__.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/robust.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/robust.py new file mode 100644 index 000000000..51596de9e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/robust.py @@ -0,0 +1,53 @@ +import time +from . import simple + + +class MQTTClient(simple.MQTTClient): + DELAY = 2 + DEBUG = False + + def delay(self, i): + time.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + + def check_msg(self, attempts=2): + while attempts: + self.sock.setblocking(False) + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() + attempts -= 1 diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/robust.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/robust.pyi new file mode 100644 index 000000000..bd876e431 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/robust.pyi @@ -0,0 +1,11 @@ +from . import simple as simple + +class MQTTClient(simple.MQTTClient): + DELAY: int + DEBUG: bool + def delay(self, i) -> None: ... + def log(self, in_reconnect, e) -> None: ... + def reconnect(self): ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0): ... + def wait_msg(self): ... + def check_msg(self, attempts: int = 2): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/simple.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/simple.py new file mode 100644 index 000000000..d9cdffc47 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/simple.py @@ -0,0 +1,220 @@ +import socket +import struct +from binascii import hexlify + + +class MQTTException(Exception): + pass + + +class MQTTClient: + def __init__( + self, + client_id, + server, + port=0, + user=None, + password=None, + keepalive=0, + ssl=None, + ssl_params={}, + ): + if port == 0: + port = 8883 if ssl else 1883 + self.client_id = client_id + self.sock = None + self.server = server + self.port = port + self.ssl = ssl + self.ssl_params = ssl_params + self.pid = 0 + self.cb = None + self.user = user + self.pswd = password + self.keepalive = keepalive + self.lw_topic = None + self.lw_msg = None + self.lw_qos = 0 + self.lw_retain = False + + def _send_str(self, s): + self.sock.write(struct.pack("!H", len(s))) + self.sock.write(s) + + def _recv_len(self): + n = 0 + sh = 0 + while 1: + b = self.sock.read(1)[0] + n |= (b & 0x7F) << sh + if not b & 0x80: + return n + sh += 7 + + def set_callback(self, f): + self.cb = f + + def set_last_will(self, topic, msg, retain=False, qos=0): + assert 0 <= qos <= 2 + assert topic + self.lw_topic = topic + self.lw_msg = msg + self.lw_qos = qos + self.lw_retain = retain + + def connect(self, clean_session=True, timeout=None): + self.sock = socket.socket() + self.sock.settimeout(timeout) + addr = socket.getaddrinfo(self.server, self.port)[0][-1] + self.sock.connect(addr) + if self.ssl is True: + # Legacy support for ssl=True and ssl_params arguments. + import ssl + + self.sock = ssl.wrap_socket(self.sock, **self.ssl_params) + elif self.ssl: + self.sock = self.ssl.wrap_socket(self.sock, server_hostname=self.server) + premsg = bytearray(b"\x10\0\0\0\0\0") + msg = bytearray(b"\x04MQTT\x04\x02\0\0") + + sz = 10 + 2 + len(self.client_id) + msg[6] = clean_session << 1 + if self.user: + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 + if self.keepalive: + assert self.keepalive < 65536 + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF + if self.lw_topic: + sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) + msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 + msg[6] |= self.lw_retain << 5 + + i = 1 + while sz > 0x7F: + premsg[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + premsg[i] = sz + + self.sock.write(premsg, i + 2) + self.sock.write(msg) + # print(hex(len(msg)), hexlify(msg, ":")) + self._send_str(self.client_id) + if self.lw_topic: + self._send_str(self.lw_topic) + self._send_str(self.lw_msg) + if self.user: + self._send_str(self.user) + self._send_str(self.pswd) + resp = self.sock.read(4) + assert resp[0] == 0x20 and resp[1] == 0x02 + if resp[3] != 0: + raise MQTTException(resp[3]) + return resp[2] & 1 + + def disconnect(self): + self.sock.write(b"\xe0\0") + self.sock.close() + + def ping(self): + self.sock.write(b"\xc0\0") + + def publish(self, topic, msg, retain=False, qos=0): + pkt = bytearray(b"\x30\0\0\0") + pkt[0] |= qos << 1 | retain + sz = 2 + len(topic) + len(msg) + if qos > 0: + sz += 2 + assert sz < 2097152 + i = 1 + while sz > 0x7F: + pkt[i] = (sz & 0x7F) | 0x80 + sz >>= 7 + i += 1 + pkt[i] = sz + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt, i + 1) + self._send_str(topic) + if qos > 0: + self.pid += 1 + pid = self.pid + struct.pack_into("!H", pkt, 0, pid) + self.sock.write(pkt, 2) + self.sock.write(msg) + if qos == 1: + while 1: + op = self.wait_msg() + if op == 0x40: + sz = self.sock.read(1) + assert sz == b"\x02" + rcv_pid = self.sock.read(2) + rcv_pid = rcv_pid[0] << 8 | rcv_pid[1] + if pid == rcv_pid: + return + elif qos == 2: + assert 0 + + def subscribe(self, topic, qos=0): + assert self.cb is not None, "Subscribe callback is not set" + pkt = bytearray(b"\x82\0\0\0") + self.pid += 1 + struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid) + # print(hex(len(pkt)), hexlify(pkt, ":")) + self.sock.write(pkt) + self._send_str(topic) + self.sock.write(qos.to_bytes(1, "little")) + while 1: + op = self.wait_msg() + if op == 0x90: + resp = self.sock.read(4) + # print(resp) + assert resp[1] == pkt[2] and resp[2] == pkt[3] + if resp[3] == 0x80: + raise MQTTException(resp[3]) + return + + # Wait for a single incoming MQTT message and process it. + # Subscribed messages are delivered to a callback previously + # set by .set_callback() method. Other (internal) MQTT + # messages processed internally. + def wait_msg(self): + res = self.sock.read(1) + self.sock.setblocking(True) + if res is None: + return None + if res == b"": + raise OSError(-1) + if res == b"\xd0": # PINGRESP + sz = self.sock.read(1)[0] + assert sz == 0 + return None + op = res[0] + if op & 0xF0 != 0x30: + return op + sz = self._recv_len() + topic_len = self.sock.read(2) + topic_len = (topic_len[0] << 8) | topic_len[1] + topic = self.sock.read(topic_len) + sz -= topic_len + 2 + if op & 6: + pid = self.sock.read(2) + pid = pid[0] << 8 | pid[1] + sz -= 2 + msg = self.sock.read(sz) + self.cb(topic, msg) + if op & 6 == 2: + pkt = bytearray(b"\x40\x02\0\0") + struct.pack_into("!H", pkt, 2, pid) + self.sock.write(pkt) + elif op & 6 == 4: + assert 0 + return op + + # Checks whether a pending message from server is available. + # If not, returns immediately with None. Otherwise, does + # the same processing as wait_msg. + def check_msg(self): + self.sock.setblocking(False) + return self.wait_msg() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/simple.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/simple.pyi new file mode 100644 index 000000000..e603f711b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/umqtt/simple.pyi @@ -0,0 +1,33 @@ +from _typeshed import Incomplete +from binascii import hexlify as hexlify + +class MQTTException(Exception): ... + +class MQTTClient: + client_id: Incomplete + sock: Incomplete + server: Incomplete + port: Incomplete + ssl: Incomplete + ssl_params: Incomplete + pid: int + cb: Incomplete + user: Incomplete + pswd: Incomplete + keepalive: Incomplete + lw_topic: Incomplete + lw_msg: Incomplete + lw_qos: int + lw_retain: bool + def __init__(self, client_id, server, port: int = 0, user=None, password=None, keepalive: int = 0, ssl=None, ssl_params={}) -> None: ... + def _send_str(self, s) -> None: ... + def _recv_len(self): ... + def set_callback(self, f) -> None: ... + def set_last_will(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def connect(self, clean_session: bool = True, timeout=None): ... + def disconnect(self) -> None: ... + def ping(self) -> None: ... + def publish(self, topic, msg, retain: bool = False, qos: int = 0) -> None: ... + def subscribe(self, topic, qos: int = 0) -> None: ... + def wait_msg(self): ... + def check_msg(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/upysh.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/upysh.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/urequests.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp32/UM_TINYS3/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/_boot.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/_boot.py new file mode 100644 index 000000000..00a0d6550 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/_boot.py @@ -0,0 +1,15 @@ +import gc + +gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4) +import vfs +from flashbdev import bdev + +if bdev: + try: + vfs.mount(bdev, "/") + except: + import inisetup + + inisetup.setup() + +gc.collect() diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/_boot.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/_boot.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/apa102.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/apa102.py new file mode 100644 index 000000000..41b7c0485 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/apa102.py @@ -0,0 +1,17 @@ +# APA102 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Robert Foss, Daniel Busch + +from esp import apa102_write +from neopixel import NeoPixel + + +class APA102(NeoPixel): + ORDER = (0, 1, 2, 3) + + def __init__(self, clock_pin, data_pin, n, bpp=4): + super().__init__(data_pin, n, bpp) + self.clock_pin = clock_pin + self.clock_pin.init(clock_pin.OUT) + + def write(self): + apa102_write(self.clock_pin, self.pin, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/apa102.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/apa102.pyi new file mode 100644 index 000000000..0bcf3724d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/apa102.pyi @@ -0,0 +1,8 @@ +from _typeshed import Incomplete +from neopixel import NeoPixel + +class APA102(NeoPixel): + ORDER: Incomplete + clock_pin: Incomplete + def __init__(self, clock_pin, data_pin, n, bpp: int = 4) -> None: ... + def write(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/dht.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/dht.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ds18x20.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/espnow.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/espnow.py new file mode 100644 index 000000000..1d2b94655 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/espnow.py @@ -0,0 +1,37 @@ +# espnow module for MicroPython on ESP8266 +# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20 + +from _espnow import * +from select import poll, POLLIN + + +class ESPNow(ESPNowBase): + # Static buffers for alloc free receipt of messages with ESPNow.irecv(). + _data = [bytearray(ADDR_LEN), bytearray(MAX_DATA_LEN)] + _none_tuple = (None, None) + + def __init__(self): + super().__init__() + self._poll = poll() # For any() method below... + self._poll.register(self, POLLIN) + + def irecv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return self._data if n else self._none_tuple + + def recv(self, timeout_ms=None): + n = self.recvinto(self._data, timeout_ms) + return [bytes(x) for x in self._data] if n else self._none_tuple + + def __iter__(self): + return self + + def __next__(self): + return self.irecv() # Use alloc free irecv() method + + def any(self): # For the ESP8266 which does not have ESPNow.any() + try: + next(self._poll.ipoll(0)) + return True + except StopIteration: + return False diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/espnow.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/espnow.pyi new file mode 100644 index 000000000..a003aca6d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/espnow.pyi @@ -0,0 +1,284 @@ +""" +ESP-NOW :doc:`asyncio` support. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/aioespnow.html +""" + +from __future__ import annotations +from _espnow import * +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Iterator, List, Tuple, Union, overload +from typing_extensions import Awaitable, Buffer, TypeAlias, TypeVar + +MAX_DATA_LEN: Incomplete = 250 +KEY_LEN: Incomplete = 16 +ADDR_LEN: Incomplete = 6 +MAX_TOTAL_PEER_NUM: Incomplete = 20 +MAX_ENCRYPT_PEER_NUM: Incomplete = 6 +_MACAddress: TypeAlias = bytes +_PeerInfo: TypeAlias = Tuple[_MACAddress, bytes, int, int, bool] + +class ESPNow(ESPNowBase, Iterator): + """ + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + """ + + _data: Incomplete + _none_tuple: Incomplete + _poll: Incomplete + def __init__(self) -> None: ... + def irecv(self, timeout_ms=None) -> Tuple[_MACAddress | bytearray | None, bytearray | None]: + """ + Works like `ESPNow.recv()` but will reuse internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + """ + ... + def recv(self, timeout_ms=None) -> Union[List, Tuple[None, None]]: + """ + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + """ + ... + # + @mp_available() # force merge + def __iter__(self) -> ESPNow: ... + @mp_available() # force merge + def __next__(self) -> Tuple[_MACAddress | None, bytes | None]: ... + def any(self) -> bool: + """ + Check if data is available to be read with `ESPNow.recv()`. + + For more sophisticated querying of available characters use `select.poll()`:: + + import select + import espnow + + e = espnow.ESPNow() + poll = select.poll() + poll.register(e, select.POLLIN) + poll.poll(timeout) + + Returns: + + ``True`` if data is available to be read, else ``False``. + """ + ... + + @overload + def config(self, rxbuf: int) -> None: ... + @overload + def config(self, timeout_ms: int) -> None: ... + @overload + def config(self, rate: int) -> None: ... + @overload + def config(self, param: str) -> int: + """ + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. This + parameter is actually *write-only* due to ESP-IDF not providing any + means for querying the radio interface's rate parameter. + + Returns: + + ``None`` or the value of the parameter being queried. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + """ + ... + + @overload + def send( + self, + mac: _MACAddress, + msg: str | bytes, + sync: bool = True, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + + @overload + def send( + self, + msg: str | bytes, + ) -> bool: + """ + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/flashbdev.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/flashbdev.py new file mode 100644 index 000000000..652fe9a4b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/flashbdev.py @@ -0,0 +1,42 @@ +import esp + + +class FlashBdev: + SEC_SIZE = 4096 + + def __init__(self, start_sec, blocks): + self.start_sec = start_sec + self.blocks = blocks + + def readblocks(self, n, buf, off=0): + # print("readblocks(%s, %x(%d), %d)" % (n, id(buf), len(buf), off)) + esp.flash_read((n + self.start_sec) * self.SEC_SIZE + off, buf) + + def writeblocks(self, n, buf, off=None): + # print("writeblocks(%s, %x(%d), %d)" % (n, id(buf), len(buf), off)) + # assert len(buf) <= self.SEC_SIZE, len(buf) + if off is None: + esp.flash_erase(n + self.start_sec) + off = 0 + esp.flash_write((n + self.start_sec) * self.SEC_SIZE + off, buf) + + def ioctl(self, op, arg): + # print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # MP_BLOCKDEV_IOCTL_BLOCK_COUNT + return self.blocks + if op == 5: # MP_BLOCKDEV_IOCTL_BLOCK_SIZE + return self.SEC_SIZE + if op == 6: # MP_BLOCKDEV_IOCTL_BLOCK_ERASE + esp.flash_erase(arg + self.start_sec) + return 0 + + +size = esp.flash_size() +if size < 1024 * 1024: + bdev = None +else: + start_sec = esp.flash_user_start() // FlashBdev.SEC_SIZE + if start_sec < 256: + start_sec += 1 # Reserve space for native code + # 20K at the flash end is reserved for SDK params storage + bdev = FlashBdev(start_sec, (size - 20480) // FlashBdev.SEC_SIZE - start_sec) diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/flashbdev.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/flashbdev.pyi new file mode 100644 index 000000000..776d6f76b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/flashbdev.pyi @@ -0,0 +1,14 @@ +from _typeshed import Incomplete + +class FlashBdev: + SEC_SIZE: int + start_sec: Incomplete + blocks: Incomplete + def __init__(self, start_sec, blocks) -> None: ... + def readblocks(self, n, buf, off: int = 0) -> None: ... + def writeblocks(self, n, buf, off=None) -> None: ... + def ioctl(self, op, arg): ... + +size: Incomplete +bdev: Incomplete +start_sec: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/inisetup.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/inisetup.py new file mode 100644 index 000000000..f97c23852 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/inisetup.py @@ -0,0 +1,68 @@ +import vfs +import network +from flashbdev import bdev + + +def wifi(): + import binascii + + ap_if = network.WLAN(network.WLAN.IF_AP) + ssid = b"MicroPython-%s" % binascii.hexlify(ap_if.config("mac")[-3:]) + ap_if.config(ssid=ssid, security=network.AUTH_WPA_WPA2_PSK, key=b"micropythoN") + + +def check_bootsec(): + buf = bytearray(bdev.SEC_SIZE) + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xFF: + empty = False + break + if empty: + return True + fs_corrupted() + + +def fs_corrupted(): + import time + import micropython + + # Allow this loop to be stopped via Ctrl-C. + micropython.kbd_intr(3) + + while 1: + print( + """\ +The filesystem starting at sector %d with size %d sectors looks corrupt. +You may want to make a flash snapshot and try to recover it. Otherwise, +format it with vfs.VfsLfs2.mkfs(bdev), or completely erase the flash and +reprogram MicroPython. +""" + % (bdev.start_sec, bdev.blocks) + ) + time.sleep(3) + + +def setup(): + check_bootsec() + print("Performing initial setup") + wifi() + vfs.VfsLfs2.mkfs(bdev) + fs = vfs.VfsLfs2(bdev) + vfs.mount(fs, "/") + with open("boot.py", "w") as f: + f.write( + """\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +import os, machine +#os.dupterm(None, 1) # disable REPL on UART(0) +import gc +#import webrepl +#webrepl.start() +gc.collect() +""" + ) + return vfs diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/inisetup.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/inisetup.pyi new file mode 100644 index 000000000..7209b1f27 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/inisetup.pyi @@ -0,0 +1,4 @@ +def wifi() -> None: ... +def check_bootsec(): ... +def fs_corrupted() -> None: ... +def setup(): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/modules.json new file mode 100644 index 000000000..6b8a63837 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/modules.json @@ -0,0 +1,88 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "esp8266", + "platform": "esp8266", + "machine": "GENERIC", + "firmware": "micropython-esp8266-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "apa102.py", + "module": "apa102" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espnow.py", + "module": "espnow" + }, + { + "file": "flashbdev.py", + "module": "flashbdev" + }, + { + "file": "inisetup.py", + "module": "inisetup" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "port_diag.py", + "module": "port_diag" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/neopixel.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ntptime.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/onewire.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/port_diag.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/port_diag.py new file mode 100644 index 000000000..36dd80567 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/port_diag.py @@ -0,0 +1,32 @@ +import esp +import uctypes +import network +import lwip + + +def main(): + ROM = uctypes.bytearray_at(0x40200000, 16) + fid = esp.flash_id() + + print("FlashROM:") + print("Flash ID: %x (Vendor: %x Device: %x)" % (fid, fid & 0xFF, fid & 0xFF00 | fid >> 16)) + + print("Flash bootloader data:") + SZ_MAP = {0: "512KB", 1: "256KB", 2: "1MB", 3: "2MB", 4: "4MB"} + FREQ_MAP = {0: "40MHZ", 1: "26MHZ", 2: "20MHz", 0xF: "80MHz"} + print("Byte @2: %02x" % ROM[2]) + print("Byte @3: %02x (Flash size: %s Flash freq: %s)" % (ROM[3], SZ_MAP.get(ROM[3] >> 4, "?"), FREQ_MAP.get(ROM[3] & 0xF))) + print("Firmware checksum:") + print(esp.check_fw()) + + print("\nNetworking:") + print("STA ifconfig:", network.WLAN(network.WLAN.IF_STA).ifconfig()) + print("AP ifconfig:", network.WLAN(network.WLAN.IF_AP).ifconfig()) + print("Free WiFi driver buffers of type:") + for i, comm in enumerate(("1,2 TX", "4 Mngmt TX(len: 0x41-0x100)", "5 Mngmt TX (len: 0-0x40)", "7", "8 RX")): + print("%d: %d (%s)" % (i, esp.esf_free_bufs(i), comm)) + print("lwIP PCBs:") + lwip.print_pcbs() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/port_diag.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/port_diag.pyi new file mode 100644 index 000000000..7e7363e79 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/port_diag.pyi @@ -0,0 +1 @@ +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ssl.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ssl.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/urequests.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/urequests.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/esp8266/GENERIC/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/_boot.py b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/_boot.py new file mode 100644 index 000000000..fa3b78043 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/_boot.py @@ -0,0 +1,36 @@ +# _boot.py +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. + +import os +import vfs +import sys +import mimxrt +from machine import Pin + +bdev = mimxrt.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/flash") +os.chdir("/flash") +sys.path.append("/flash") +sys.path.append("/flash/lib") + +# do not mount the SD card if SKIPSD exists. +try: + os.stat("SKIPSD") +except: + try: + from machine import SDCard + + sdcard = SDCard(1) + + fat = vfs.VfsFat(sdcard) + vfs.mount(fat, "/sdcard") + os.chdir("/sdcard") + sys.path.append("/sdcard") + except: + pass # Fail silently diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/_boot.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/dht.py b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/dht.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/ds18x20.py b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/modules.json new file mode 100644 index 000000000..0e2693e84 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/modules.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "mimxrt", + "platform": "mimxrt", + "machine": "GENERIC", + "firmware": "micropython-mimxrt-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/onewire.py b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/_boot.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/_boot.py new file mode 100644 index 000000000..fa3b78043 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/_boot.py @@ -0,0 +1,36 @@ +# _boot.py +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. + +import os +import vfs +import sys +import mimxrt +from machine import Pin + +bdev = mimxrt.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/flash") +os.chdir("/flash") +sys.path.append("/flash") +sys.path.append("/flash/lib") + +# do not mount the SD card if SKIPSD exists. +try: + os.stat("SKIPSD") +except: + try: + from machine import SDCard + + sdcard = SDCard(1) + + fat = vfs.VfsFat(sdcard) + vfs.mount(fat, "/sdcard") + os.chdir("/sdcard") + sys.path.append("/sdcard") + except: + pass # Fail silently diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/_boot.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/dht.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/dht.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ds18x20.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/modules.json b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/modules.json new file mode 100644 index 000000000..4d6def57a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/modules.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "mimxrt", + "platform": "mimxrt", + "machine": "MIMXRT1020_EVK", + "firmware": "micropython-mimxrt-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ntptime.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/onewire.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/onewire.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/removed.txt b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ssl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ssl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/urequests.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/urequests.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1020_EVK/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/_boot.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/_boot.py new file mode 100644 index 000000000..fa3b78043 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/_boot.py @@ -0,0 +1,36 @@ +# _boot.py +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. + +import os +import vfs +import sys +import mimxrt +from machine import Pin + +bdev = mimxrt.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/flash") +os.chdir("/flash") +sys.path.append("/flash") +sys.path.append("/flash/lib") + +# do not mount the SD card if SKIPSD exists. +try: + os.stat("SKIPSD") +except: + try: + from machine import SDCard + + sdcard = SDCard(1) + + fat = vfs.VfsFat(sdcard) + vfs.mount(fat, "/sdcard") + os.chdir("/sdcard") + sys.path.append("/sdcard") + except: + pass # Fail silently diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/_boot.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/dht.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/dht.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ds18x20.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/modules.json b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/modules.json new file mode 100644 index 000000000..433ba768b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/modules.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "mimxrt", + "platform": "mimxrt", + "machine": "MIMXRT1050_EVK", + "firmware": "micropython-mimxrt-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ntptime.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/onewire.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/onewire.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/removed.txt b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ssl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ssl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/urequests.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/urequests.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1050_EVK/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/_boot.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/_boot.py new file mode 100644 index 000000000..fa3b78043 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/_boot.py @@ -0,0 +1,36 @@ +# _boot.py +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. + +import os +import vfs +import sys +import mimxrt +from machine import Pin + +bdev = mimxrt.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/flash") +os.chdir("/flash") +sys.path.append("/flash") +sys.path.append("/flash/lib") + +# do not mount the SD card if SKIPSD exists. +try: + os.stat("SKIPSD") +except: + try: + from machine import SDCard + + sdcard = SDCard(1) + + fat = vfs.VfsFat(sdcard) + vfs.mount(fat, "/sdcard") + os.chdir("/sdcard") + sys.path.append("/sdcard") + except: + pass # Fail silently diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/_boot.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/dht.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/dht.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ds18x20.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/modules.json b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/modules.json new file mode 100644 index 000000000..1e2598fb7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/modules.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "mimxrt", + "platform": "mimxrt", + "machine": "MIMXRT1060_EVK", + "firmware": "micropython-mimxrt-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ntptime.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/onewire.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/onewire.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/removed.txt b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ssl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ssl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/urequests.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/urequests.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1060_EVK/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/_boot.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/_boot.py new file mode 100644 index 000000000..fa3b78043 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/_boot.py @@ -0,0 +1,36 @@ +# _boot.py +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. + +import os +import vfs +import sys +import mimxrt +from machine import Pin + +bdev = mimxrt.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/flash") +os.chdir("/flash") +sys.path.append("/flash") +sys.path.append("/flash/lib") + +# do not mount the SD card if SKIPSD exists. +try: + os.stat("SKIPSD") +except: + try: + from machine import SDCard + + sdcard = SDCard(1) + + fat = vfs.VfsFat(sdcard) + vfs.mount(fat, "/sdcard") + os.chdir("/sdcard") + sys.path.append("/sdcard") + except: + pass # Fail silently diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/_boot.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/dht.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/dht.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ds18x20.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/modules.json b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/modules.json new file mode 100644 index 000000000..d17c773b5 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/modules.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "mimxrt", + "platform": "mimxrt", + "machine": "MIMXRT1064_EVK", + "firmware": "micropython-mimxrt-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ntptime.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/onewire.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/onewire.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/removed.txt b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ssl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ssl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/urequests.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/urequests.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1064_EVK/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/_boot.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/_boot.py new file mode 100644 index 000000000..fa3b78043 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/_boot.py @@ -0,0 +1,36 @@ +# _boot.py +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. + +import os +import vfs +import sys +import mimxrt +from machine import Pin + +bdev = mimxrt.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/flash") +os.chdir("/flash") +sys.path.append("/flash") +sys.path.append("/flash/lib") + +# do not mount the SD card if SKIPSD exists. +try: + os.stat("SKIPSD") +except: + try: + from machine import SDCard + + sdcard = SDCard(1) + + fat = vfs.VfsFat(sdcard) + vfs.mount(fat, "/sdcard") + os.chdir("/sdcard") + sys.path.append("/sdcard") + except: + pass # Fail silently diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/_boot.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/dht.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/dht.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ds18x20.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/modules.json b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/modules.json new file mode 100644 index 000000000..c29f727c2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/modules.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "mimxrt", + "platform": "mimxrt", + "machine": "MIMXRT1170_EVK", + "firmware": "micropython-mimxrt-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ntptime.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/onewire.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/onewire.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/removed.txt b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ssl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ssl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/urequests.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/urequests.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/MIMXRT1170_EVK/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/_boot.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/_boot.py new file mode 100644 index 000000000..fa3b78043 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/_boot.py @@ -0,0 +1,36 @@ +# _boot.py +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. + +import os +import vfs +import sys +import mimxrt +from machine import Pin + +bdev = mimxrt.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/flash") +os.chdir("/flash") +sys.path.append("/flash") +sys.path.append("/flash/lib") + +# do not mount the SD card if SKIPSD exists. +try: + os.stat("SKIPSD") +except: + try: + from machine import SDCard + + sdcard = SDCard(1) + + fat = vfs.VfsFat(sdcard) + vfs.mount(fat, "/sdcard") + os.chdir("/sdcard") + sys.path.append("/sdcard") + except: + pass # Fail silently diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/_boot.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/dht.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/dht.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ds18x20.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/modules.json b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/modules.json new file mode 100644 index 000000000..b7fe1140f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/modules.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "mimxrt", + "platform": "mimxrt", + "machine": "SEEED_ARCH_MIX", + "firmware": "micropython-mimxrt-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ntptime.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/onewire.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/onewire.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/removed.txt b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ssl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ssl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/urequests.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/urequests.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/_boot.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/_boot.py new file mode 100644 index 000000000..fa3b78043 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/_boot.py @@ -0,0 +1,36 @@ +# _boot.py +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. + +import os +import vfs +import sys +import mimxrt +from machine import Pin + +bdev = mimxrt.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/flash") +os.chdir("/flash") +sys.path.append("/flash") +sys.path.append("/flash/lib") + +# do not mount the SD card if SKIPSD exists. +try: + os.stat("SKIPSD") +except: + try: + from machine import SDCard + + sdcard = SDCard(1) + + fat = vfs.VfsFat(sdcard) + vfs.mount(fat, "/sdcard") + os.chdir("/sdcard") + sys.path.append("/sdcard") + except: + pass # Fail silently diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/_boot.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/dht.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/dht.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ds18x20.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/modules.json b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/modules.json new file mode 100644 index 000000000..c70042640 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/modules.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "mimxrt", + "platform": "mimxrt", + "machine": "TEENSY41", + "firmware": "micropython-mimxrt-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ntptime.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/onewire.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/onewire.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/removed.txt b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ssl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ssl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/urequests.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/urequests.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/mimxrt/TEENSY41/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.py b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.py new file mode 100644 index 000000000..601f9558e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.py @@ -0,0 +1,23 @@ +import vfs, nrf + +try: + from vfs import VfsLfs1 + + vfs.VfsLfs1.mkfs(nrf.Flash()) +except ImportError: + try: + from vfs import VfsLfs2 + + vfs.VfsLfs2.mkfs(nrf.Flash()) + except ImportError: + try: + from vfs import VfsFat + + vfs.VfsFat.mkfs(nrf.Flash()) + except ImportError: + pass + except OSError as e: + if e.args[0] == 5: # I/O Error + flashbdev_size = (nrf.Flash.ioctl(4, 0) * nrf.Flash.ioctl(5, 0)) // 1024 + print() + print("Is `FS_SIZE=%iK` enough for FAT filesystem?" % flashbdev_size) diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.pyi b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.pyi new file mode 100644 index 000000000..5a34f5f24 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/_mkfs.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete +from vfs import VfsFat as VfsFat, VfsLfs1 as VfsLfs1, VfsLfs2 as VfsLfs2 + +flashbdev_size: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.py b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.py new file mode 100644 index 000000000..4f8f92c4c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.py @@ -0,0 +1,634 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Basic example usage: + +import time +from bmi270 import BMI270 +from machine import Pin, SPI, I2C + +# Init in I2C mode. +imu = BMI270(I2C(1, scl=Pin(15), sda=Pin(14))) + +# Or init in SPI mode. +# TODO: Not supported yet. +# imu = BMI270(SPI(5), cs=Pin(10)) + +while (True): + print('Accelerometer: x:{:>6.3f} y:{:>6.3f} z:{:>6.3f}'.format(*imu.accel())) + print('Gyroscope: x:{:>6.3f} y:{:>6.3f} z:{:>6.3f}'.format(*imu.gyro())) + print('Magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.magnet())) + print("") + time.sleep_ms(100) +""" + +import array +import time +from micropython import const + +_DEFAULT_ADDR = 0x68 +_CHIP_ID = 0x00 +_STATUS = 0x21 +_INIT_ADDR_0 = 0x5B +_INIT_ADDR_1 = 0x5C +_DATA_8 = 0x0C +_DATA_14 = 0x12 +_CMD = 0x7E +_CONFIG_DATA = const( + b"\xc8\x2e\x00\x2e\x80\x2e\x3d\xb1\xc8\x2e\x00\x2e\x80\x2e\x91\x03\x80\x2e\xbc" + b"\xb0\x80\x2e\xa3\x03\xc8\x2e\x00\x2e\x80\x2e\x00\xb0\x50\x30\x21\x2e\x59\xf5" + b"\x10\x30\x21\x2e\x6a\xf5\x80\x2e\x3b\x03\x00\x00\x00\x00\x08\x19\x01\x00\x22" + b"\x00\x75\x00\x00\x10\x00\x10\xd1\x00\xb3\x43\x80\x2e\x00\xc1\x80\x2e\x00\xc1" + b"\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00" + b"\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e" + b"\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80" + b"\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1" + b"\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00" + b"\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e" + b"\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80" + b"\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1" + b"\x80\x2e\x00\xc1\x80\x2e\x00\xc1\xe0\x5f\x00\x00\x00\x00\x01\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x92\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x08\x19\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x05" + b"\xe0\xaa\x38\x05\xe0\x90\x30\xfa\x00\x96\x00\x4b\x09\x11\x00\x11\x00\x02\x00" + b"\x2d\x01\xd4\x7b\x3b\x01\xdb\x7a\x04\x00\x3f\x7b\xcd\x6c\xc3\x04\x85\x09\xc3" + b"\x04\xec\xe6\x0c\x46\x01\x00\x27\x00\x19\x00\x96\x00\xa0\x00\x01\x00\x0c\x00" + b"\xf0\x3c\x00\x01\x01\x00\x03\x00\x01\x00\x0e\x00\x00\x00\x32\x00\x05\x00\xee" + b"\x06\x04\x00\xc8\x00\x00\x00\x04\x00\xa8\x05\xee\x06\x00\x04\xbc\x02\xb3\x00" + b"\x85\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\xb4\x00\x01\x00\xb9\x00\x01\x00\x98\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x01\x00\x80\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x2e\x00\xc1\xfd\x2d\xde" + b"\x00\xeb\x00\xda\x00\x00\x0c\xff\x0f\x00\x04\xc0\x00\x5b\xf5\xc9\x01\x1e\xf2" + b"\x80\x00\x3f\xff\x19\xf4\x58\xf5\x66\xf5\x64\xf5\xc0\xf1\xf0\x00\xe0\x00\xcd" + b"\x01\xd3\x01\xdb\x01\xff\x7f\xff\x01\xe4\x00\x74\xf7\xf3\x00\xfa\x00\xff\x3f" + b"\xca\x03\x6c\x38\x56\xfe\x44\xfd\xbc\x02\xf9\x06\x00\xfc\x12\x02\xae\x01\x58" + b"\xfa\x9a\xfd\x77\x05\xbb\x02\x96\x01\x95\x01\x7f\x01\x82\x01\x89\x01\x87\x01" + b"\x88\x01\x8a\x01\x8c\x01\x8f\x01\x8d\x01\x92\x01\x91\x01\xdd\x00\x9f\x01\x7e" + b"\x01\xdb\x00\xb6\x01\x70\x69\x26\xd3\x9c\x07\x1f\x05\x9d\x00\x00\x08\xbc\x05" + b"\x37\xfa\xa2\x01\xaa\x01\xa1\x01\xa8\x01\xa0\x01\xa8\x05\xb4\x01\xb4\x01\xce" + b"\x00\xd0\x00\xfc\x00\xc5\x01\xff\xfb\xb1\x00\x00\x38\x00\x30\xfd\xf5\xfc\xf5" + b"\xcd\x01\xa0\x00\x5f\xff\x00\x40\xff\x00\x00\x80\x6d\x0f\xeb\x00\x7f\xff\xc2" + b"\xf5\x68\xf7\xb3\xf1\x67\x0f\x5b\x0f\x61\x0f\x80\x0f\x58\xf7\x5b\xf7\x83\x0f" + b"\x86\x00\x72\x0f\x85\x0f\xc6\xf1\x7f\x0f\x6c\xf7\x00\xe0\x00\xff\xd1\xf5\x87" + b"\x0f\x8a\x0f\xff\x03\xf0\x3f\x8b\x00\x8e\x00\x90\x00\xb9\x00\x2d\xf5\xca\xf5" + b"\xcb\x01\x20\xf2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x50\x98\x2e" + b"\xd7\x0e\x50\x32\x98\x2e\xfa\x03\x00\x30\xf0\x7f\x00\x2e\x00\x2e\xd0\x2e\x00" + b"\x2e\x01\x80\x08\xa2\xfb\x2f\x98\x2e\xba\x03\x21\x2e\x19\x00\x01\x2e\xee\x00" + b"\x00\xb2\x07\x2f\x01\x2e\x19\x00\x00\xb2\x03\x2f\x01\x50\x03\x52\x98\x2e\x07" + b"\xcc\x01\x2e\xdd\x00\x00\xb2\x27\x2f\x05\x2e\x8a\x00\x05\x52\x98\x2e\xc7\xc1" + b"\x03\x2e\xe9\x00\x40\xb2\xf0\x7f\x08\x2f\x01\x2e\x19\x00\x00\xb2\x04\x2f\x00" + b"\x30\x21\x2e\xe9\x00\x98\x2e\xb4\xb1\x01\x2e\x18\x00\x00\xb2\x10\x2f\x05\x50" + b"\x98\x2e\x4d\xc3\x05\x50\x98\x2e\x5a\xc7\x98\x2e\xf9\xb4\x98\x2e\x54\xb2\x98" + b"\x2e\x67\xb6\x98\x2e\x17\xb2\x10\x30\x21\x2e\x77\x00\x01\x2e\xef\x00\x00\xb2" + b"\x04\x2f\x98\x2e\x7a\xb7\x00\x30\x21\x2e\xef\x00\x01\x2e\xd4\x00\x04\xae\x0b" + b"\x2f\x01\x2e\xdd\x00\x00\xb2\x07\x2f\x05\x52\x98\x2e\x8e\x0e\x00\xb2\x02\x2f" + b"\x10\x30\x21\x2e\x7d\x00\x01\x2e\x7d\x00\x00\x90\x90\x2e\xf1\x02\x01\x2e\xd7" + b"\x00\x00\xb2\x04\x2f\x98\x2e\x2f\x0e\x00\x30\x21\x2e\x7b\x00\x01\x2e\x7b\x00" + b"\x00\xb2\x12\x2f\x01\x2e\xd4\x00\x00\x90\x02\x2f\x98\x2e\x1f\x0e\x09\x2d\x98" + b"\x2e\x81\x0d\x01\x2e\xd4\x00\x04\x90\x02\x2f\x50\x32\x98\x2e\xfa\x03\x00\x30" + b"\x21\x2e\x7b\x00\x01\x2e\x7c\x00\x00\xb2\x90\x2e\x09\x03\x01\x2e\x7c\x00\x01" + b"\x31\x01\x08\x00\xb2\x04\x2f\x98\x2e\x47\xcb\x10\x30\x21\x2e\x77\x00\x81\x30" + b"\x01\x2e\x7c\x00\x01\x08\x00\xb2\x61\x2f\x03\x2e\x89\x00\x01\x2e\xd4\x00\x98" + b"\xbc\x98\xb8\x05\xb2\x0f\x58\x23\x2f\x07\x90\x09\x54\x00\x30\x37\x2f\x15\x41" + b"\x04\x41\xdc\xbe\x44\xbe\xdc\xba\x2c\x01\x61\x00\x0f\x56\x4a\x0f\x0c\x2f\xd1" + b"\x42\x94\xb8\xc1\x42\x11\x30\x05\x2e\x6a\xf7\x2c\xbd\x2f\xb9\x80\xb2\x08\x22" + b"\x98\x2e\xc3\xb7\x21\x2d\x61\x30\x23\x2e\xd4\x00\x98\x2e\xc3\xb7\x00\x30\x21" + b"\x2e\x5a\xf5\x18\x2d\xe1\x7f\x50\x30\x98\x2e\xfa\x03\x0f\x52\x07\x50\x50\x42" + b"\x70\x30\x0d\x54\x42\x42\x7e\x82\xe2\x6f\x80\xb2\x42\x42\x05\x2f\x21\x2e\xd4" + b"\x00\x10\x30\x98\x2e\xc3\xb7\x03\x2d\x60\x30\x21\x2e\xd4\x00\x01\x2e\xd4\x00" + b"\x06\x90\x18\x2f\x01\x2e\x76\x00\x0b\x54\x07\x52\xe0\x7f\x98\x2e\x7a\xc1\xe1" + b"\x6f\x08\x1a\x40\x30\x08\x2f\x21\x2e\xd4\x00\x20\x30\x98\x2e\xaf\xb7\x50\x32" + b"\x98\x2e\xfa\x03\x05\x2d\x98\x2e\x38\x0e\x00\x30\x21\x2e\xd4\x00\x00\x30\x21" + b"\x2e\x7c\x00\x18\x2d\x01\x2e\xd4\x00\x03\xaa\x01\x2f\x98\x2e\x45\x0e\x01\x2e" + b"\xd4\x00\x3f\x80\x03\xa2\x01\x2f\x00\x2e\x02\x2d\x98\x2e\x5b\x0e\x30\x30\x98" + b"\x2e\xce\xb7\x00\x30\x21\x2e\x7d\x00\x50\x32\x98\x2e\xfa\x03\x01\x2e\x77\x00" + b"\x00\xb2\x24\x2f\x98\x2e\xf5\xcb\x03\x2e\xd5\x00\x11\x54\x01\x0a\xbc\x84\x83" + b"\x86\x21\x2e\xc9\x01\xe0\x40\x13\x52\xc4\x40\x82\x40\xa8\xb9\x52\x42\x43\xbe" + b"\x53\x42\x04\x0a\x50\x42\xe1\x7f\xf0\x31\x41\x40\xf2\x6f\x25\xbd\x08\x08\x02" + b"\x0a\xd0\x7f\x98\x2e\xa8\xcf\x06\xbc\xd1\x6f\xe2\x6f\x08\x0a\x80\x42\x98\x2e" + b"\x58\xb7\x00\x30\x21\x2e\xee\x00\x21\x2e\x77\x00\x21\x2e\xdd\x00\x80\x2e\xf4" + b"\x01\x1a\x24\x22\x00\x80\x2e\xec\x01\x10\x50\xfb\x7f\x98\x2e\xf3\x03\x57\x50" + b"\xfb\x6f\x01\x30\x71\x54\x11\x42\x42\x0e\xfc\x2f\xc0\x2e\x01\x42\xf0\x5f\x80" + b"\x2e\x00\xc1\xfd\x2d\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x01" + b"\x34\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x20\x50\xe7\x7f\xf6\x7f\x06\x32\x0f\x2e\x61\xf5\xfe\x09\xc0\xb3\x04" + b"\x2f\x17\x30\x2f\x2e\xef\x00\x2d\x2e\x61\xf5\xf6\x6f\xe7\x6f\xe0\x5f\xc8\x2e" + b"\x20\x50\xe7\x7f\xf6\x7f\x46\x30\x0f\x2e\xa4\xf1\xbe\x09\x80\xb3\x06\x2f\x0d" + b"\x2e\xd4\x00\x84\xaf\x02\x2f\x16\x30\x2d\x2e\x7b\x00\x86\x30\x2d\x2e\x60\xf5" + b"\xf6\x6f\xe7\x6f\xe0\x5f\xc8\x2e\x01\x2e\x77\xf7\x09\xbc\x0f\xb8\x00\xb2\x10" + b"\x50\xfb\x7f\x10\x30\x0b\x2f\x03\x2e\x8a\x00\x96\xbc\x9f\xb8\x40\xb2\x05\x2f" + b"\x03\x2e\x68\xf7\x9e\xbc\x9f\xb8\x40\xb2\x07\x2f\x03\x2e\x7e\x00\x41\x90\x01" + b"\x2f\x98\x2e\xdc\x03\x03\x2c\x00\x30\x21\x2e\x7e\x00\xfb\x6f\xf0\x5f\xb8\x2e" + b"\x20\x50\xe0\x7f\xfb\x7f\x00\x2e\x27\x50\x98\x2e\x3b\xc8\x29\x50\x98\x2e\xa7" + b"\xc8\x01\x50\x98\x2e\x55\xcc\xe1\x6f\x2b\x50\x98\x2e\xe0\xc9\xfb\x6f\x00\x30" + b"\xe0\x5f\x21\x2e\x7e\x00\xb8\x2e\x73\x50\x01\x30\x57\x54\x11\x42\x42\x0e\xfc" + b"\x2f\xb8\x2e\x21\x2e\x59\xf5\x10\x30\xc0\x2e\x21\x2e\x4a\xf1\x90\x50\xf7\x7f" + b"\xe6\x7f\xd5\x7f\xc4\x7f\xb3\x7f\xa1\x7f\x90\x7f\x82\x7f\x7b\x7f\x98\x2e\x35" + b"\xb7\x00\xb2\x90\x2e\x97\xb0\x03\x2e\x8f\x00\x07\x2e\x91\x00\x05\x2e\xb1\x00" + b"\x3f\xba\x9f\xb8\x01\x2e\xb1\x00\xa3\xbd\x4c\x0a\x05\x2e\xb1\x00\x04\xbe\xbf" + b"\xb9\xcb\x0a\x4f\xba\x22\xbd\x01\x2e\xb3\x00\xdc\x0a\x2f\xb9\x03\x2e\xb8\x00" + b"\x0a\xbe\x9a\x0a\xcf\xb9\x9b\xbc\x01\x2e\x97\x00\x9f\xb8\x93\x0a\x0f\xbc\x91" + b"\x0a\x0f\xb8\x90\x0a\x25\x2e\x18\x00\x05\x2e\xc1\xf5\x2e\xbd\x2e\xb9\x01\x2e" + b"\x19\x00\x31\x30\x8a\x04\x00\x90\x07\x2f\x01\x2e\xd4\x00\x04\xa2\x03\x2f\x01" + b"\x2e\x18\x00\x00\xb2\x0c\x2f\x19\x50\x05\x52\x98\x2e\x4d\xb7\x05\x2e\x78\x00" + b"\x80\x90\x10\x30\x01\x2f\x21\x2e\x78\x00\x25\x2e\xdd\x00\x98\x2e\x3e\xb7\x00" + b"\xb2\x02\x30\x01\x30\x04\x2f\x01\x2e\x19\x00\x00\xb2\x00\x2f\x21\x30\x01\x2e" + b"\xea\x00\x08\x1a\x0e\x2f\x23\x2e\xea\x00\x33\x30\x1b\x50\x0b\x09\x01\x40\x17" + b"\x56\x46\xbe\x4b\x08\x4c\x0a\x01\x42\x0a\x80\x15\x52\x01\x42\x00\x2e\x01\x2e" + b"\x18\x00\x00\xb2\x1f\x2f\x03\x2e\xc0\xf5\xf0\x30\x48\x08\x47\xaa\x74\x30\x07" + b"\x2e\x7a\x00\x61\x22\x4b\x1a\x05\x2f\x07\x2e\x66\xf5\xbf\xbd\xbf\xb9\xc0\x90" + b"\x0b\x2f\x1d\x56\x2b\x30\xd2\x42\xdb\x42\x01\x04\xc2\x42\x04\xbd\xfe\x80\x81" + b"\x84\x23\x2e\x7a\x00\x02\x42\x02\x32\x25\x2e\x62\xf5\x05\x2e\xd6\x00\x81\x84" + b"\x25\x2e\xd6\x00\x02\x31\x25\x2e\x60\xf5\x05\x2e\x8a\x00\x0b\x50\x90\x08\x80" + b"\xb2\x0b\x2f\x05\x2e\xca\xf5\xf0\x3e\x90\x08\x25\x2e\xca\xf5\x05\x2e\x59\xf5" + b"\xe0\x3f\x90\x08\x25\x2e\x59\xf5\x90\x6f\xa1\x6f\xb3\x6f\xc4\x6f\xd5\x6f\xe6" + b"\x6f\xf7\x6f\x7b\x6f\x82\x6f\x70\x5f\xc8\x2e\xc0\x50\x90\x7f\xe5\x7f\xd4\x7f" + b"\xc3\x7f\xb1\x7f\xa2\x7f\x87\x7f\xf6\x7f\x7b\x7f\x00\x2e\x01\x2e\x60\xf5\x60" + b"\x7f\x98\x2e\x35\xb7\x02\x30\x63\x6f\x15\x52\x50\x7f\x62\x7f\x5a\x2c\x02\x32" + b"\x1a\x09\x00\xb3\x14\x2f\x00\xb2\x03\x2f\x09\x2e\x18\x00\x00\x91\x0c\x2f\x43" + b"\x7f\x98\x2e\x97\xb7\x1f\x50\x02\x8a\x02\x32\x04\x30\x25\x2e\x64\xf5\x15\x52" + b"\x50\x6f\x43\x6f\x44\x43\x25\x2e\x60\xf5\xd9\x08\xc0\xb2\x36\x2f\x98\x2e\x3e" + b"\xb7\x00\xb2\x06\x2f\x01\x2e\x19\x00\x00\xb2\x02\x2f\x50\x6f\x00\x90\x0a\x2f" + b"\x01\x2e\x79\x00\x00\x90\x19\x2f\x10\x30\x21\x2e\x79\x00\x00\x30\x98\x2e\xdc" + b"\x03\x13\x2d\x01\x2e\xc3\xf5\x0c\xbc\x0f\xb8\x12\x30\x10\x04\x03\xb0\x26\x25" + b"\x21\x50\x03\x52\x98\x2e\x4d\xb7\x10\x30\x21\x2e\xee\x00\x02\x30\x60\x7f\x25" + b"\x2e\x79\x00\x60\x6f\x00\x90\x05\x2f\x00\x30\x21\x2e\xea\x00\x15\x50\x21\x2e" + b"\x64\xf5\x15\x52\x23\x2e\x60\xf5\x02\x32\x50\x6f\x00\x90\x02\x2f\x03\x30\x27" + b"\x2e\x78\x00\x07\x2e\x60\xf5\x1a\x09\x00\x91\xa3\x2f\x19\x09\x00\x91\xa0\x2f" + b"\x90\x6f\xa2\x6f\xb1\x6f\xc3\x6f\xd4\x6f\xe5\x6f\x7b\x6f\xf6\x6f\x87\x6f\x40" + b"\x5f\xc8\x2e\xc0\x50\xe7\x7f\xf6\x7f\x26\x30\x0f\x2e\x61\xf5\x2f\x2e\x7c\x00" + b"\x0f\x2e\x7c\x00\xbe\x09\xa2\x7f\x80\x7f\x80\xb3\xd5\x7f\xc4\x7f\xb3\x7f\x91" + b"\x7f\x7b\x7f\x0b\x2f\x23\x50\x1a\x25\x12\x40\x42\x7f\x74\x82\x12\x40\x52\x7f" + b"\x00\x2e\x00\x40\x60\x7f\x98\x2e\x6a\xd6\x81\x30\x01\x2e\x7c\x00\x01\x08\x00" + b"\xb2\x42\x2f\x03\x2e\x89\x00\x01\x2e\x89\x00\x97\xbc\x06\xbc\x9f\xb8\x0f\xb8" + b"\x00\x90\x23\x2e\xd8\x00\x10\x30\x01\x30\x2a\x2f\x03\x2e\xd4\x00\x44\xb2\x05" + b"\x2f\x47\xb2\x00\x30\x2d\x2f\x21\x2e\x7c\x00\x2b\x2d\x03\x2e\xfd\xf5\x9e\xbc" + b"\x9f\xb8\x40\x90\x14\x2f\x03\x2e\xfc\xf5\x99\xbc\x9f\xb8\x40\x90\x0e\x2f\x03" + b"\x2e\x49\xf1\x25\x54\x4a\x08\x40\x90\x08\x2f\x98\x2e\x35\xb7\x00\xb2\x10\x30" + b"\x03\x2f\x50\x30\x21\x2e\xd4\x00\x10\x2d\x98\x2e\xaf\xb7\x00\x30\x21\x2e\x7c" + b"\x00\x0a\x2d\x05\x2e\x69\xf7\x2d\xbd\x2f\xb9\x80\xb2\x01\x2f\x21\x2e\x7d\x00" + b"\x23\x2e\x7c\x00\xe0\x31\x21\x2e\x61\xf5\xf6\x6f\xe7\x6f\x80\x6f\xa2\x6f\xb3" + b"\x6f\xc4\x6f\xd5\x6f\x7b\x6f\x91\x6f\x40\x5f\xc8\x2e\x60\x51\x0a\x25\x36\x88" + b"\xf4\x7f\xeb\x7f\x00\x32\x31\x52\x32\x30\x13\x30\x98\x2e\x15\xcb\x0a\x25\x33" + b"\x84\xd2\x7f\x43\x30\x05\x50\x2d\x52\x98\x2e\x95\xc1\xd2\x6f\x27\x52\x98\x2e" + b"\xd7\xc7\x2a\x25\xb0\x86\xc0\x7f\xd3\x7f\xaf\x84\x29\x50\xf1\x6f\x98\x2e\x4d" + b"\xc8\x2a\x25\xae\x8a\xaa\x88\xf2\x6e\x2b\x50\xc1\x6f\xd3\x6f\xf4\x7f\x98\x2e" + b"\xb6\xc8\xe0\x6e\x00\xb2\x32\x2f\x33\x54\x83\x86\xf1\x6f\xc3\x7f\x04\x30\x30" + b"\x30\xf4\x7f\xd0\x7f\xb2\x7f\xe3\x30\xc5\x6f\x56\x40\x45\x41\x28\x08\x03\x14" + b"\x0e\xb4\x08\xbc\x82\x40\x10\x0a\x2f\x54\x26\x05\x91\x7f\x44\x28\xa3\x7f\x98" + b"\x2e\xd9\xc0\x08\xb9\x33\x30\x53\x09\xc1\x6f\xd3\x6f\xf4\x6f\x83\x17\x47\x40" + b"\x6c\x15\xb2\x6f\xbe\x09\x75\x0b\x90\x42\x45\x42\x51\x0e\x32\xbc\x02\x89\xa1" + b"\x6f\x7e\x86\xf4\x7f\xd0\x7f\xb2\x7f\x04\x30\x91\x6f\xd6\x2f\xeb\x6f\xa0\x5e" + b"\xb8\x2e\x03\x2e\x97\x00\x1b\xbc\x60\x50\x9f\xbc\x0c\xb8\xf0\x7f\x40\xb2\xeb" + b"\x7f\x2b\x2f\x03\x2e\x7f\x00\x41\x40\x01\x2e\xc8\x00\x01\x1a\x11\x2f\x37\x58" + b"\x23\x2e\xc8\x00\x10\x41\xa0\x7f\x38\x81\x01\x41\xd0\x7f\xb1\x7f\x98\x2e\x64" + b"\xcf\xd0\x6f\x07\x80\xa1\x6f\x11\x42\x00\x2e\xb1\x6f\x01\x42\x11\x30\x01\x2e" + b"\xfc\x00\x00\xa8\x03\x30\xcb\x22\x4a\x25\x01\x2e\x7f\x00\x3c\x89\x35\x52\x05" + b"\x54\x98\x2e\xc4\xce\xc1\x6f\xf0\x6f\x98\x2e\x95\xcf\x04\x2d\x01\x30\xf0\x6f" + b"\x98\x2e\x95\xcf\xeb\x6f\xa0\x5f\xb8\x2e\x03\x2e\xb3\x00\x02\x32\xf0\x30\x03" + b"\x31\x30\x50\x8a\x08\x08\x08\xcb\x08\xe0\x7f\x80\xb2\xf3\x7f\xdb\x7f\x25\x2f" + b"\x03\x2e\xca\x00\x41\x90\x04\x2f\x01\x30\x23\x2e\xca\x00\x98\x2e\x3f\x03\xc0" + b"\xb2\x05\x2f\x03\x2e\xda\x00\x00\x30\x41\x04\x23\x2e\xda\x00\x98\x2e\x92\xb2" + b"\x10\x25\xf0\x6f\x00\xb2\x05\x2f\x01\x2e\xda\x00\x02\x30\x10\x04\x21\x2e\xda" + b"\x00\x40\xb2\x01\x2f\x23\x2e\xc8\x01\xdb\x6f\xe0\x6f\xd0\x5f\x80\x2e\x95\xcf" + b"\x01\x30\xe0\x6f\x98\x2e\x95\xcf\x11\x30\x23\x2e\xca\x00\xdb\x6f\xd0\x5f\xb8" + b"\x2e\xd0\x50\x0a\x25\x33\x84\x55\x50\xd2\x7f\xe2\x7f\x03\x8c\xc0\x7f\xbb\x7f" + b"\x00\x30\x05\x5a\x39\x54\x51\x41\xa5\x7f\x96\x7f\x80\x7f\x98\x2e\xd9\xc0\x05" + b"\x30\xf5\x7f\x20\x25\x91\x6f\x3b\x58\x3d\x5c\x3b\x56\x98\x2e\x67\xcc\xc1\x6f" + b"\xd5\x6f\x52\x40\x50\x43\xc1\x7f\xd5\x7f\x10\x25\x98\x2e\xfe\xc9\x10\x25\x98" + b"\x2e\x74\xc0\x86\x6f\x30\x28\x92\x6f\x82\x8c\xa5\x6f\x6f\x52\x69\x0e\x39\x54" + b"\xdb\x2f\x19\xa0\x15\x30\x03\x2f\x00\x30\x21\x2e\x81\x01\x0a\x2d\x01\x2e\x81" + b"\x01\x05\x28\x42\x36\x21\x2e\x81\x01\x02\x0e\x01\x2f\x98\x2e\xf3\x03\x57\x50" + b"\x12\x30\x01\x40\x98\x2e\xfe\xc9\x51\x6f\x0b\x5c\x8e\x0e\x3b\x6f\x57\x58\x02" + b"\x30\x21\x2e\x95\x01\x45\x6f\x2a\x8d\xd2\x7f\xcb\x7f\x13\x2f\x02\x30\x3f\x50" + b"\xd2\x7f\xa8\x0e\x0e\x2f\xc0\x6f\x53\x54\x02\x00\x51\x54\x42\x0e\x10\x30\x59" + b"\x52\x02\x30\x01\x2f\x00\x2e\x03\x2d\x50\x42\x42\x42\x12\x30\xd2\x7f\x80\xb2" + b"\x03\x2f\x00\x30\x21\x2e\x80\x01\x12\x2d\x01\x2e\xc9\x00\x02\x80\x05\x2e\x80" + b"\x01\x11\x30\x91\x28\x00\x40\x25\x2e\x80\x01\x10\x0e\x05\x2f\x01\x2e\x7f\x01" + b"\x01\x90\x01\x2f\x98\x2e\xf3\x03\x00\x2e\xa0\x41\x01\x90\xa6\x7f\x90\x2e\xe3" + b"\xb4\x01\x2e\x95\x01\x00\xa8\x90\x2e\xe3\xb4\x5b\x54\x95\x80\x82\x40\x80\xb2" + b"\x02\x40\x2d\x8c\x3f\x52\x96\x7f\x90\x2e\xc2\xb3\x29\x0e\x76\x2f\x01\x2e\xc9" + b"\x00\x00\x40\x81\x28\x45\x52\xb3\x30\x98\x2e\x0f\xca\x5d\x54\x80\x7f\x00\x2e" + b"\xa1\x40\x72\x7f\x82\x80\x82\x40\x60\x7f\x98\x2e\xfe\xc9\x10\x25\x98\x2e\x74" + b"\xc0\x62\x6f\x05\x30\x87\x40\xc0\x91\x04\x30\x05\x2f\x05\x2e\x83\x01\x80\xb2" + b"\x14\x30\x00\x2f\x04\x30\x05\x2e\xc9\x00\x73\x6f\x81\x40\xe2\x40\x69\x04\x11" + b"\x0f\xe1\x40\x16\x30\xfe\x29\xcb\x40\x02\x2f\x83\x6f\x83\x0f\x22\x2f\x47\x56" + b"\x13\x0f\x12\x30\x77\x2f\x49\x54\x42\x0e\x12\x30\x73\x2f\x00\x91\x0a\x2f\x01" + b"\x2e\x8b\x01\x19\xa8\x02\x30\x6c\x2f\x63\x50\x00\x2e\x17\x42\x05\x42\x68\x2c" + b"\x12\x30\x0b\x25\x08\x0f\x50\x30\x02\x2f\x21\x2e\x83\x01\x03\x2d\x40\x30\x21" + b"\x2e\x83\x01\x2b\x2e\x85\x01\x5a\x2c\x12\x30\x00\x91\x2b\x25\x04\x2f\x63\x50" + b"\x02\x30\x17\x42\x17\x2c\x02\x42\x98\x2e\xfe\xc9\x10\x25\x98\x2e\x74\xc0\x05" + b"\x2e\xc9\x00\x81\x84\x5b\x30\x82\x40\x37\x2e\x83\x01\x02\x0e\x07\x2f\x5f\x52" + b"\x40\x30\x62\x40\x41\x40\x91\x0e\x01\x2f\x21\x2e\x83\x01\x05\x30\x2b\x2e\x85" + b"\x01\x12\x30\x36\x2c\x16\x30\x15\x25\x81\x7f\x98\x2e\xfe\xc9\x10\x25\x98\x2e" + b"\x74\xc0\x19\xa2\x16\x30\x15\x2f\x05\x2e\x97\x01\x80\x6f\x82\x0e\x05\x2f\x01" + b"\x2e\x86\x01\x06\x28\x21\x2e\x86\x01\x0b\x2d\x03\x2e\x87\x01\x5f\x54\x4e\x28" + b"\x91\x42\x00\x2e\x82\x40\x90\x0e\x01\x2f\x21\x2e\x88\x01\x02\x30\x13\x2c\x05" + b"\x30\xc0\x6f\x08\x1c\xa8\x0f\x16\x30\x05\x30\x5b\x50\x09\x2f\x02\x80\x2d\x2e" + b"\x82\x01\x05\x42\x05\x80\x00\x2e\x02\x42\x3e\x80\x00\x2e\x06\x42\x02\x30\x90" + b"\x6f\x3e\x88\x01\x40\x04\x41\x4c\x28\x01\x42\x07\x80\x10\x25\x24\x40\x00\x40" + b"\x00\xa8\xf5\x22\x23\x29\x44\x42\x7a\x82\x7e\x88\x43\x40\x04\x41\x00\xab\xf5" + b"\x23\xdf\x28\x43\x42\xd9\xa0\x14\x2f\x00\x90\x02\x2f\xd2\x6f\x81\xb2\x05\x2f" + b"\x63\x54\x06\x28\x90\x42\x85\x42\x09\x2c\x02\x30\x5b\x50\x03\x80\x29\x2e\x7e" + b"\x01\x2b\x2e\x82\x01\x05\x42\x12\x30\x2b\x2e\x83\x01\x45\x82\x00\x2e\x40\x40" + b"\x7a\x82\x02\xa0\x08\x2f\x63\x50\x3b\x30\x15\x42\x05\x42\x37\x80\x37\x2e\x7e" + b"\x01\x05\x42\x12\x30\x01\x2e\xc9\x00\x02\x8c\x40\x40\x84\x41\x7a\x8c\x04\x0f" + b"\x03\x2f\x01\x2e\x8b\x01\x19\xa4\x04\x2f\x2b\x2e\x82\x01\x98\x2e\xf3\x03\x12" + b"\x30\x81\x90\x61\x52\x08\x2f\x65\x42\x65\x42\x43\x80\x39\x84\x82\x88\x05\x42" + b"\x45\x42\x85\x42\x05\x43\x00\x2e\x80\x41\x00\x90\x90\x2e\xe1\xb4\x65\x54\xc1" + b"\x6f\x80\x40\x00\xb2\x43\x58\x69\x50\x44\x2f\x55\x5c\xb7\x87\x8c\x0f\x0d\x2e" + b"\x96\x01\xc4\x40\x36\x2f\x41\x56\x8b\x0e\x2a\x2f\x0b\x52\xa1\x0e\x0a\x2f\x05" + b"\x2e\x8f\x01\x14\x25\x98\x2e\xfe\xc9\x4b\x54\x02\x0f\x69\x50\x05\x30\x65\x54" + b"\x15\x2f\x03\x2e\x8e\x01\x4d\x5c\x8e\x0f\x3a\x2f\x05\x2e\x8f\x01\x98\x2e\xfe" + b"\xc9\x4f\x54\x82\x0f\x05\x30\x69\x50\x65\x54\x30\x2f\x6d\x52\x15\x30\x42\x8c" + b"\x45\x42\x04\x30\x2b\x2c\x84\x43\x6b\x52\x42\x8c\x00\x2e\x85\x43\x15\x30\x24" + b"\x2c\x45\x42\x8e\x0f\x20\x2f\x0d\x2e\x8e\x01\xb1\x0e\x1c\x2f\x23\x2e\x8e\x01" + b"\x1a\x2d\x0e\x0e\x17\x2f\xa1\x0f\x15\x2f\x23\x2e\x8d\x01\x13\x2d\x98\x2e\x74" + b"\xc0\x43\x54\xc2\x0e\x0a\x2f\x65\x50\x04\x80\x0b\x30\x06\x82\x0b\x42\x79\x80" + b"\x41\x40\x12\x30\x25\x2e\x8c\x01\x01\x42\x05\x30\x69\x50\x65\x54\x84\x82\x43" + b"\x84\xbe\x8c\x84\x40\x86\x41\x26\x29\x94\x42\xbe\x8e\xd5\x7f\x19\xa1\x43\x40" + b"\x0b\x2e\x8c\x01\x84\x40\xc7\x41\x5d\x29\x27\x29\x45\x42\x84\x42\xc2\x7f\x01" + b"\x2f\xc0\xb3\x1d\x2f\x05\x2e\x94\x01\x99\xa0\x01\x2f\x80\xb3\x13\x2f\x80\xb3" + b"\x18\x2f\xc0\xb3\x16\x2f\x12\x40\x01\x40\x92\x7f\x98\x2e\x74\xc0\x92\x6f\x10" + b"\x0f\x20\x30\x03\x2f\x10\x30\x21\x2e\x7e\x01\x0a\x2d\x21\x2e\x7e\x01\x07\x2d" + b"\x20\x30\x21\x2e\x7e\x01\x03\x2d\x10\x30\x21\x2e\x7e\x01\xc2\x6f\x01\x2e\xc9" + b"\x00\xbc\x84\x02\x80\x82\x40\x00\x40\x90\x0e\xd5\x6f\x02\x2f\x15\x30\x98\x2e" + b"\xf3\x03\x41\x91\x05\x30\x07\x2f\x67\x50\x3d\x80\x2b\x2e\x8f\x01\x05\x42\x04" + b"\x80\x00\x2e\x05\x42\x02\x2c\x00\x30\x00\x30\xa2\x6f\x98\x8a\x86\x40\x80\xa7" + b"\x05\x2f\x98\x2e\xf3\x03\xc0\x30\x21\x2e\x95\x01\x06\x25\x1a\x25\xe2\x6f\x76" + b"\x82\x96\x40\x56\x43\x51\x0e\xfb\x2f\xbb\x6f\x30\x5f\xb8\x2e\x01\x2e\xb8\x00" + b"\x01\x31\x41\x08\x40\xb2\x20\x50\xf2\x30\x02\x08\xfb\x7f\x01\x30\x10\x2f\x05" + b"\x2e\xcc\x00\x81\x90\xe0\x7f\x03\x2f\x23\x2e\xcc\x00\x98\x2e\x55\xb6\x98\x2e" + b"\x1d\xb5\x10\x25\xfb\x6f\xe0\x6f\xe0\x5f\x80\x2e\x95\xcf\x98\x2e\x95\xcf\x10" + b"\x30\x21\x2e\xcc\x00\xfb\x6f\xe0\x5f\xb8\x2e\x00\x51\x05\x58\xeb\x7f\x2a\x25" + b"\x89\x52\x6f\x5a\x89\x50\x13\x41\x06\x40\xb3\x01\x16\x42\xcb\x16\x06\x40\xf3" + b"\x02\x13\x42\x65\x0e\xf5\x2f\x05\x40\x14\x30\x2c\x29\x04\x42\x08\xa1\x00\x30" + b"\x90\x2e\x52\xb6\xb3\x88\xb0\x8a\xb6\x84\xa4\x7f\xc4\x7f\xb5\x7f\xd5\x7f\x92" + b"\x7f\x73\x30\x04\x30\x55\x40\x42\x40\x8a\x17\xf3\x08\x6b\x01\x90\x02\x53\xb8" + b"\x4b\x82\xad\xbe\x71\x7f\x45\x0a\x09\x54\x84\x7f\x98\x2e\xd9\xc0\xa3\x6f\x7b" + b"\x54\xd0\x42\xa3\x7f\xf2\x7f\x60\x7f\x20\x25\x71\x6f\x75\x5a\x77\x58\x79\x5c" + b"\x75\x56\x98\x2e\x67\xcc\xb1\x6f\x62\x6f\x50\x42\xb1\x7f\xb3\x30\x10\x25\x98" + b"\x2e\x0f\xca\x84\x6f\x20\x29\x71\x6f\x92\x6f\xa5\x6f\x76\x82\x6a\x0e\x73\x30" + b"\x00\x30\xd0\x2f\xd2\x6f\xd1\x7f\xb4\x7f\x98\x2e\x2b\xb7\x15\xbd\x0b\xb8\x02" + b"\x0a\xc2\x6f\xc0\x7f\x98\x2e\x2b\xb7\x15\xbd\x0b\xb8\x42\x0a\xc0\x6f\x08\x17" + b"\x41\x18\x89\x16\xe1\x18\xd0\x18\xa1\x7f\x27\x25\x16\x25\x98\x2e\x79\xc0\x8b" + b"\x54\x90\x7f\xb3\x30\x82\x40\x80\x90\x0d\x2f\x7d\x52\x92\x6f\x98\x2e\x0f\xca" + b"\xb2\x6f\x90\x0e\x06\x2f\x8b\x50\x14\x30\x42\x6f\x51\x6f\x14\x42\x12\x42\x01" + b"\x42\x00\x2e\x31\x6f\x98\x2e\x74\xc0\x41\x6f\x80\x7f\x98\x2e\x74\xc0\x82\x6f" + b"\x10\x04\x43\x52\x01\x0f\x05\x2e\xcb\x00\x00\x30\x04\x30\x21\x2f\x51\x6f\x43" + b"\x58\x8c\x0e\x04\x30\x1c\x2f\x85\x88\x41\x6f\x04\x41\x8c\x0f\x04\x30\x16\x2f" + b"\x84\x88\x00\x2e\x04\x41\x04\x05\x8c\x0e\x04\x30\x0f\x2f\x82\x88\x31\x6f\x04" + b"\x41\x04\x05\x8c\x0e\x04\x30\x08\x2f\x83\x88\x00\x2e\x04\x41\x8c\x0f\x04\x30" + b"\x02\x2f\x21\x2e\xad\x01\x14\x30\x00\x91\x14\x2f\x03\x2e\xa1\x01\x41\x90\x0e" + b"\x2f\x03\x2e\xad\x01\x14\x30\x4c\x28\x23\x2e\xad\x01\x46\xa0\x06\x2f\x81\x84" + b"\x8d\x52\x48\x82\x82\x40\x21\x2e\xa1\x01\x42\x42\x5c\x2c\x02\x30\x05\x2e\xaa" + b"\x01\x80\xb2\x02\x30\x55\x2f\x03\x2e\xa9\x01\x92\x6f\xb3\x30\x98\x2e\x0f\xca" + b"\xb2\x6f\x90\x0f\x00\x30\x02\x30\x4a\x2f\xa2\x6f\x87\x52\x91\x00\x85\x52\x51" + b"\x0e\x02\x2f\x00\x2e\x43\x2c\x02\x30\xc2\x6f\x7f\x52\x91\x0e\x02\x30\x3c\x2f" + b"\x51\x6f\x81\x54\x98\x2e\xfe\xc9\x10\x25\xb3\x30\x21\x25\x98\x2e\x0f\xca\x32" + b"\x6f\xc0\x7f\xb3\x30\x12\x25\x98\x2e\x0f\xca\x42\x6f\xb0\x7f\xb3\x30\x12\x25" + b"\x98\x2e\x0f\xca\xb2\x6f\x90\x28\x83\x52\x98\x2e\xfe\xc9\xc2\x6f\x90\x0f\x00" + b"\x30\x02\x30\x1d\x2f\x05\x2e\xa1\x01\x80\xb2\x12\x30\x0f\x2f\x42\x6f\x03\x2e" + b"\xab\x01\x91\x0e\x02\x30\x12\x2f\x52\x6f\x03\x2e\xac\x01\x91\x0f\x02\x30\x0c" + b"\x2f\x21\x2e\xaa\x01\x0a\x2c\x12\x30\x03\x2e\xcb\x00\x8d\x58\x08\x89\x41\x40" + b"\x11\x43\x00\x43\x25\x2e\xa1\x01\xd4\x6f\x8f\x52\x00\x43\x3a\x89\x00\x2e\x10" + b"\x43\x10\x43\x61\x0e\xfb\x2f\x03\x2e\xa0\x01\x11\x1a\x02\x2f\x02\x25\x21\x2e" + b"\xa0\x01\xeb\x6f\x00\x5f\xb8\x2e\x91\x52\x10\x30\x02\x30\x95\x56\x52\x42\x4b" + b"\x0e\xfc\x2f\x8d\x54\x88\x82\x93\x56\x80\x42\x53\x42\x40\x42\x42\x86\x83\x54" + b"\xc0\x2e\xc2\x42\x00\x2e\xa3\x52\x00\x51\x52\x40\x47\x40\x1a\x25\x01\x2e\x97" + b"\x00\x8f\xbe\x72\x86\xfb\x7f\x0b\x30\x7c\xbf\xa5\x50\x10\x08\xdf\xba\x70\x88" + b"\xf8\xbf\xcb\x42\xd3\x7f\x6c\xbb\xfc\xbb\xc5\x0a\x90\x7f\x1b\x7f\x0b\x43\xc0" + b"\xb2\xe5\x7f\xb7\x7f\xa6\x7f\xc4\x7f\x90\x2e\x1c\xb7\x07\x2e\xd2\x00\xc0\xb2" + b"\x0b\x2f\x97\x52\x01\x2e\xcd\x00\x82\x7f\x98\x2e\xbb\xcc\x0b\x30\x37\x2e\xd2" + b"\x00\x82\x6f\x90\x6f\x1a\x25\x00\xb2\x8b\x7f\x14\x2f\xa6\xbd\x25\xbd\xb6\xb9" + b"\x2f\xb9\x80\xb2\xd4\xb0\x0c\x2f\x99\x54\x9b\x56\x0b\x30\x0b\x2e\xb1\x00\xa1" + b"\x58\x9b\x42\xdb\x42\x6c\x09\x2b\x2e\xb1\x00\x8b\x42\xcb\x42\x86\x7f\x73\x84" + b"\xa7\x56\xc3\x08\x39\x52\x05\x50\x72\x7f\x63\x7f\x98\x2e\xc2\xc0\xe1\x6f\x62" + b"\x6f\xd1\x0a\x01\x2e\xcd\x00\xd5\x6f\xc4\x6f\x72\x6f\x97\x52\x9d\x5c\x98\x2e" + b"\x06\xcd\x23\x6f\x90\x6f\x99\x52\xc0\xb2\x04\xbd\x54\x40\xaf\xb9\x45\x40\xe1" + b"\x7f\x02\x30\x06\x2f\xc0\xb2\x02\x30\x03\x2f\x9b\x5c\x12\x30\x94\x43\x85\x43" + b"\x03\xbf\x6f\xbb\x80\xb3\x20\x2f\x06\x6f\x26\x01\x16\x6f\x6e\x03\x45\x42\xc0" + b"\x90\x29\x2e\xce\x00\x9b\x52\x14\x2f\x9b\x5c\x00\x2e\x93\x41\x86\x41\xe3\x04" + b"\xae\x07\x80\xab\x04\x2f\x80\x91\x0a\x2f\x86\x6f\x73\x0f\x07\x2f\x83\x6f\xc0" + b"\xb2\x04\x2f\x54\x42\x45\x42\x12\x30\x04\x2c\x11\x30\x02\x2c\x11\x30\x11\x30" + b"\x02\xbc\x0f\xb8\xd2\x7f\x00\xb2\x0a\x2f\x01\x2e\xfc\x00\x05\x2e\xc7\x01\x10" + b"\x1a\x02\x2f\x21\x2e\xc7\x01\x03\x2d\x02\x2c\x01\x30\x01\x30\xb0\x6f\x98\x2e" + b"\x95\xcf\xd1\x6f\xa0\x6f\x98\x2e\x95\xcf\xe2\x6f\x9f\x52\x01\x2e\xce\x00\x82" + b"\x40\x50\x42\x0c\x2c\x42\x42\x11\x30\x23\x2e\xd2\x00\x01\x30\xb0\x6f\x98\x2e" + b"\x95\xcf\xa0\x6f\x01\x30\x98\x2e\x95\xcf\x00\x2e\xfb\x6f\x00\x5f\xb8\x2e\x83" + b"\x86\x01\x30\x00\x30\x94\x40\x24\x18\x06\x00\x53\x0e\x4f\x02\xf9\x2f\xb8\x2e" + b"\xa9\x52\x00\x2e\x60\x40\x41\x40\x0d\xbc\x98\xbc\xc0\x2e\x01\x0a\x0f\xb8\xab" + b"\x52\x53\x3c\x52\x40\x40\x40\x4b\x00\x82\x16\x26\xb9\x01\xb8\x41\x40\x10\x08" + b"\x97\xb8\x01\x08\xc0\x2e\x11\x30\x01\x08\x43\x86\x25\x40\x04\x40\xd8\xbe\x2c" + b"\x0b\x22\x11\x54\x42\x03\x80\x4b\x0e\xf6\x2f\xb8\x2e\x9f\x50\x10\x50\xad\x52" + b"\x05\x2e\xd3\x00\xfb\x7f\x00\x2e\x13\x40\x93\x42\x41\x0e\xfb\x2f\x98\x2e\xa5" + b"\xb7\x98\x2e\x87\xcf\x01\x2e\xd9\x00\x00\xb2\xfb\x6f\x0b\x2f\x01\x2e\x69\xf7" + b"\xb1\x3f\x01\x08\x01\x30\xf0\x5f\x23\x2e\xd9\x00\x21\x2e\x69\xf7\x80\x2e\x7a" + b"\xb7\xf0\x5f\xb8\x2e\x01\x2e\xc0\xf8\x03\x2e\xfc\xf5\x15\x54\xaf\x56\x82\x08" + b"\x0b\x2e\x69\xf7\xcb\x0a\xb1\x58\x80\x90\xdd\xbe\x4c\x08\x5f\xb9\x59\x22\x80" + b"\x90\x07\x2f\x03\x34\xc3\x08\xf2\x3a\x0a\x08\x02\x35\xc0\x90\x4a\x0a\x48\x22" + b"\xc0\x2e\x23\x2e\xfc\xf5\x10\x50\xfb\x7f\x98\x2e\x56\xc7\x98\x2e\x49\xc3\x10" + b"\x30\xfb\x6f\xf0\x5f\x21\x2e\xcc\x00\x21\x2e\xca\x00\xb8\x2e\x03\x2e\xd3\x00" + b"\x16\xb8\x02\x34\x4a\x0c\x21\x2e\x2d\xf5\xc0\x2e\x23\x2e\xd3\x00\x03\xbc\x21" + b"\x2e\xd5\x00\x03\x2e\xd5\x00\x40\xb2\x10\x30\x21\x2e\x77\x00\x01\x30\x05\x2f" + b"\x05\x2e\xd8\x00\x80\x90\x01\x2f\x23\x2e\x6f\xf5\xc0\x2e\x21\x2e\xd9\x00\x11" + b"\x30\x81\x08\x01\x2e\x6a\xf7\x71\x3f\x23\xbd\x01\x08\x02\x0a\xc0\x2e\x21\x2e" + b"\x6a\xf7\x30\x25\x00\x30\x21\x2e\x5a\xf5\x10\x50\x21\x2e\x7b\x00\x21\x2e\x7c" + b"\x00\xfb\x7f\x98\x2e\xc3\xb7\x40\x30\x21\x2e\xd4\x00\xfb\x6f\xf0\x5f\x03\x25" + b"\x80\x2e\xaf\xb7\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00" + b"\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e" + b"\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80" + b"\x2e\x00\xc1\x80\x2e\x00\xc1\x01\x2e\x5d\xf7\x08\xbc\x80\xac\x0e\xbb\x02\x2f" + b"\x00\x30\x41\x04\x82\x06\xc0\xa4\x00\x30\x11\x2f\x40\xa9\x03\x2f\x40\x91\x0d" + b"\x2f\x00\xa7\x0b\x2f\x80\xb3\xb3\x58\x02\x2f\x90\xa1\x26\x13\x20\x23\x80\x90" + b"\x10\x30\x01\x2f\xcc\x0e\x00\x2f\x00\x30\xb8\x2e\xb5\x50\x18\x08\x08\xbc\x88" + b"\xb6\x0d\x17\xc6\xbd\x56\xbc\xb7\x58\xda\xba\x04\x01\x1d\x0a\x10\x50\x05\x30" + b"\x32\x25\x45\x03\xfb\x7f\xf6\x30\x21\x25\x98\x2e\x37\xca\x16\xb5\x9a\xbc\x06" + b"\xb8\x80\xa8\x41\x0a\x0e\x2f\x80\x90\x02\x2f\x2d\x50\x48\x0f\x09\x2f\xbf\xa0" + b"\x04\x2f\xbf\x90\x06\x2f\xb7\x54\xca\x0f\x03\x2f\x00\x2e\x02\x2c\xb7\x52\x2d" + b"\x52\xf2\x33\x98\x2e\xd9\xc0\xfb\x6f\xf1\x37\xc0\x2e\x01\x08\xf0\x5f\xbf\x56" + b"\xb9\x54\xd0\x40\xc4\x40\x0b\x2e\xfd\xf3\xbf\x52\x90\x42\x94\x42\x95\x42\x05" + b"\x30\xc1\x50\x0f\x88\x06\x40\x04\x41\x96\x42\xc5\x42\x48\xbe\x73\x30\x0d\x2e" + b"\xd8\x00\x4f\xba\x84\x42\x03\x42\x81\xb3\x02\x2f\x2b\x2e\x6f\xf5\x06\x2d\x05" + b"\x2e\x77\xf7\xbd\x56\x93\x08\x25\x2e\x77\xf7\xbb\x54\x25\x2e\xc2\xf5\x07\x2e" + b"\xfd\xf3\x42\x30\xb4\x33\xda\x0a\x4c\x00\x27\x2e\xfd\xf3\x43\x40\xd4\x3f\xdc" + b"\x08\x43\x42\x00\x2e\x00\x2e\x43\x40\x24\x30\xdc\x0a\x43\x42\x04\x80\x03\x2e" + b"\xfd\xf3\x4a\x0a\x23\x2e\xfd\xf3\x61\x34\xc0\x2e\x01\x42\x00\x2e\x60\x50\x1a" + b"\x25\x7a\x86\xe0\x7f\xf3\x7f\x03\x25\xc3\x52\x41\x84\xdb\x7f\x33\x30\x98\x2e" + b"\x16\xc2\x1a\x25\x7d\x82\xf0\x6f\xe2\x6f\x32\x25\x16\x40\x94\x40\x26\x01\x85" + b"\x40\x8e\x17\xc4\x42\x6e\x03\x95\x42\x41\x0e\xf4\x2f\xdb\x6f\xa0\x5f\xb8\x2e" + b"\xb0\x51\xfb\x7f\x98\x2e\xe8\x0d\x5a\x25\x98\x2e\x0f\x0e\xcb\x58\x32\x87\xc4" + b"\x7f\x65\x89\x6b\x8d\xc5\x5a\x65\x7f\xe1\x7f\x83\x7f\xa6\x7f\x74\x7f\xd0\x7f" + b"\xb6\x7f\x94\x7f\x17\x30\xc7\x52\xc9\x54\x51\x7f\x00\x2e\x85\x6f\x42\x7f\x00" + b"\x2e\x51\x41\x45\x81\x42\x41\x13\x40\x3b\x8a\x00\x40\x4b\x04\xd0\x06\xc0\xac" + b"\x85\x7f\x02\x2f\x02\x30\x51\x04\xd3\x06\x41\x84\x05\x30\x5d\x02\xc9\x16\xdf" + b"\x08\xd3\x00\x8d\x02\xaf\xbc\xb1\xb9\x59\x0a\x65\x6f\x11\x43\xa1\xb4\x52\x41" + b"\x53\x41\x01\x43\x34\x7f\x65\x7f\x26\x31\xe5\x6f\xd4\x6f\x98\x2e\x37\xca\x32" + b"\x6f\x75\x6f\x83\x40\x42\x41\x23\x7f\x12\x7f\xf6\x30\x40\x25\x51\x25\x98\x2e" + b"\x37\xca\x14\x6f\x20\x05\x70\x6f\x25\x6f\x69\x07\xa2\x6f\x31\x6f\x0b\x30\x04" + b"\x42\x9b\x42\x8b\x42\x55\x42\x32\x7f\x40\xa9\xc3\x6f\x71\x7f\x02\x30\xd0\x40" + b"\xc3\x7f\x03\x2f\x40\x91\x15\x2f\x00\xa7\x13\x2f\x00\xa4\x11\x2f\x84\xbd\x98" + b"\x2e\x79\xca\x55\x6f\xb7\x54\x54\x41\x82\x00\xf3\x3f\x45\x41\xcb\x02\xf6\x30" + b"\x98\x2e\x37\xca\x35\x6f\xa4\x6f\x41\x43\x03\x2c\x00\x43\xa4\x6f\x35\x6f\x17" + b"\x30\x42\x6f\x51\x6f\x93\x40\x42\x82\x00\x41\xc3\x00\x03\x43\x51\x7f\x00\x2e" + b"\x94\x40\x41\x41\x4c\x02\xc4\x6f\xd1\x56\x63\x0e\x74\x6f\x51\x43\xa5\x7f\x8a" + b"\x2f\x09\x2e\xd8\x00\x01\xb3\x21\x2f\xcb\x58\x90\x6f\x13\x41\xb6\x6f\xe4\x7f" + b"\x00\x2e\x91\x41\x14\x40\x92\x41\x15\x40\x17\x2e\x6f\xf5\xb6\x7f\xd0\x7f\xcb" + b"\x7f\x98\x2e\x00\x0c\x07\x15\xc2\x6f\x14\x0b\x29\x2e\x6f\xf5\xc3\xa3\xc1\x8f" + b"\xe4\x6f\xd0\x6f\xe6\x2f\x14\x30\x05\x2e\x6f\xf5\x14\x0b\x29\x2e\x6f\xf5\x18" + b"\x2d\xcd\x56\x04\x32\xb5\x6f\x1c\x01\x51\x41\x52\x41\xc3\x40\xb5\x7f\xe4\x7f" + b"\x98\x2e\x1f\x0c\xe4\x6f\x21\x87\x00\x43\x04\x32\xcf\x54\x5a\x0e\xef\x2f\x15" + b"\x54\x09\x2e\x77\xf7\x22\x0b\x29\x2e\x77\xf7\xfb\x6f\x50\x5e\xb8\x2e\x10\x50" + b"\x01\x2e\xd4\x00\x00\xb2\xfb\x7f\x51\x2f\x01\xb2\x48\x2f\x02\xb2\x42\x2f\x03" + b"\x90\x56\x2f\xd7\x52\x79\x80\x42\x40\x81\x84\x00\x40\x42\x42\x98\x2e\x93\x0c" + b"\xd9\x54\xd7\x50\xa1\x40\x98\xbd\x82\x40\x3e\x82\xda\x0a\x44\x40\x8b\x16\xe3" + b"\x00\x53\x42\x00\x2e\x43\x40\x9a\x02\x52\x42\x00\x2e\x41\x40\x15\x54\x4a\x0e" + b"\x3a\x2f\x3a\x82\x00\x30\x41\x40\x21\x2e\x85\x0f\x40\xb2\x0a\x2f\x98\x2e\xb1" + b"\x0c\x98\x2e\x45\x0e\x98\x2e\x5b\x0e\xfb\x6f\xf0\x5f\x00\x30\x80\x2e\xce\xb7" + b"\xdd\x52\xd3\x54\x42\x42\x4f\x84\x73\x30\xdb\x52\x83\x42\x1b\x30\x6b\x42\x23" + b"\x30\x27\x2e\xd7\x00\x37\x2e\xd4\x00\x21\x2e\xd6\x00\x7a\x84\x17\x2c\x42\x42" + b"\x30\x30\x21\x2e\xd4\x00\x12\x2d\x21\x30\x00\x30\x23\x2e\xd4\x00\x21\x2e\x7b" + b"\xf7\x0b\x2d\x17\x30\x98\x2e\x51\x0c\xd5\x50\x0c\x82\x72\x30\x2f\x2e\xd4\x00" + b"\x25\x2e\x7b\xf7\x40\x42\x00\x2e\xfb\x6f\xf0\x5f\xb8\x2e\x70\x50\x0a\x25\x39" + b"\x86\xfb\x7f\xe1\x32\x62\x30\x98\x2e\xc2\xc4\xb5\x56\xa5\x6f\xab\x08\x91\x6f" + b"\x4b\x08\xdf\x56\xc4\x6f\x23\x09\x4d\xba\x93\xbc\x8c\x0b\xd1\x6f\x0b\x09\xcb" + b"\x52\xe1\x5e\x56\x42\xaf\x09\x4d\xba\x23\xbd\x94\x0a\xe5\x6f\x68\xbb\xeb\x08" + b"\xbd\xb9\x63\xbe\xfb\x6f\x52\x42\xe3\x0a\xc0\x2e\x43\x42\x90\x5f\xd1\x50\x03" + b"\x2e\x25\xf3\x13\x40\x00\x40\x9b\xbc\x9b\xb4\x08\xbd\xb8\xb9\x98\xbc\xda\x0a" + b"\x08\xb6\x89\x16\xc0\x2e\x19\x00\x62\x02\x10\x50\xfb\x7f\x98\x2e\x81\x0d\x01" + b"\x2e\xd4\x00\x31\x30\x08\x04\xfb\x6f\x01\x30\xf0\x5f\x23\x2e\xd6\x00\x21\x2e" + b"\xd7\x00\xb8\x2e\x01\x2e\xd7\x00\x03\x2e\xd6\x00\x48\x0e\x01\x2f\x80\x2e\x1f" + b"\x0e\xb8\x2e\xe3\x50\x21\x34\x01\x42\x82\x30\xc1\x32\x25\x2e\x62\xf5\x01\x00" + b"\x22\x30\x01\x40\x4a\x0a\x01\x42\xb8\x2e\xe3\x54\xf0\x3b\x83\x40\xd8\x08\xe5" + b"\x52\x83\x42\x00\x30\x83\x30\x50\x42\xc4\x32\x27\x2e\x64\xf5\x94\x00\x50\x42" + b"\x40\x42\xd3\x3f\x84\x40\x7d\x82\xe3\x08\x40\x42\x83\x42\xb8\x2e\xdd\x52\x00" + b"\x30\x40\x42\x7c\x86\xb9\x52\x09\x2e\x70\x0f\xbf\x54\xc4\x42\xd3\x86\x54\x40" + b"\x55\x40\x94\x42\x85\x42\x21\x2e\xd7\x00\x42\x40\x25\x2e\xfd\xf3\xc0\x42\x7e" + b"\x82\x05\x2e\x7d\x00\x80\xb2\x14\x2f\x05\x2e\x89\x00\x27\xbd\x2f\xb9\x80\x90" + b"\x02\x2f\x21\x2e\x6f\xf5\x0c\x2d\x07\x2e\x71\x0f\x14\x30\x1c\x09\x05\x2e\x77" + b"\xf7\xbd\x56\x47\xbe\x93\x08\x94\x0a\x25\x2e\x77\xf7\xe7\x54\x50\x42\x4a\x0e" + b"\xfc\x2f\xb8\x2e\x50\x50\x02\x30\x43\x86\xe5\x50\xfb\x7f\xe3\x7f\xd2\x7f\xc0" + b"\x7f\xb1\x7f\x00\x2e\x41\x40\x00\x40\x48\x04\x98\x2e\x74\xc0\x1e\xaa\xd3\x6f" + b"\x14\x30\xb1\x6f\xe3\x22\xc0\x6f\x52\x40\xe4\x6f\x4c\x0e\x12\x42\xd3\x7f\xeb" + b"\x2f\x03\x2e\x86\x0f\x40\x90\x11\x30\x03\x2f\x23\x2e\x86\x0f\x02\x2c\x00\x30" + b"\xd0\x6f\xfb\x6f\xb0\x5f\xb8\x2e\x40\x50\xf1\x7f\x0a\x25\x3c\x86\xeb\x7f\x41" + b"\x33\x22\x30\x98\x2e\xc2\xc4\xd3\x6f\xf4\x30\xdc\x09\x47\x58\xc2\x6f\x94\x09" + b"\xeb\x58\x6a\xbb\xdc\x08\xb4\xb9\xb1\xbd\xe9\x5a\x95\x08\x21\xbd\xf6\xbf\x77" + b"\x0b\x51\xbe\xf1\x6f\xeb\x6f\x52\x42\x54\x42\xc0\x2e\x43\x42\xc0\x5f\x50\x50" + b"\xf5\x50\x31\x30\x11\x42\xfb\x7f\x7b\x30\x0b\x42\x11\x30\x02\x80\x23\x33\x01" + b"\x42\x03\x00\x07\x2e\x80\x03\x05\x2e\xd3\x00\x23\x52\xe2\x7f\xd3\x7f\xc0\x7f" + b"\x98\x2e\xb6\x0e\xd1\x6f\x08\x0a\x1a\x25\x7b\x86\xd0\x7f\x01\x33\x12\x30\x98" + b"\x2e\xc2\xc4\xd1\x6f\x08\x0a\x00\xb2\x0d\x2f\xe3\x6f\x01\x2e\x80\x03\x51\x30" + b"\xc7\x86\x23\x2e\x21\xf2\x08\xbc\xc0\x42\x98\x2e\xa5\xb7\x00\x2e\x00\x2e\xd0" + b"\x2e\xb0\x6f\x0b\xb8\x03\x2e\x1b\x00\x08\x1a\xb0\x7f\x70\x30\x04\x2f\x21\x2e" + b"\x21\xf2\x00\x2e\x00\x2e\xd0\x2e\x98\x2e\x6d\xc0\x98\x2e\x5d\xc0\xed\x50\x98" + b"\x2e\x44\xcb\xef\x50\x98\x2e\x46\xc3\xf1\x50\x98\x2e\x53\xc7\x35\x50\x98\x2e" + b"\x64\xcf\x10\x30\x98\x2e\xdc\x03\x20\x26\xc0\x6f\x02\x31\x12\x42\xab\x33\x0b" + b"\x42\x37\x80\x01\x30\x01\x42\xf3\x37\xf7\x52\xfb\x50\x44\x40\xa2\x0a\x42\x42" + b"\x8b\x31\x09\x2e\x5e\xf7\xf9\x54\xe3\x08\x83\x42\x1b\x42\x23\x33\x4b\x00\xbc" + b"\x84\x0b\x40\x33\x30\x83\x42\x0b\x42\xe0\x7f\xd1\x7f\x98\x2e\x58\xb7\xd1\x6f" + b"\x80\x30\x40\x42\x03\x30\xe0\x6f\xf3\x54\x04\x30\x00\x2e\x00\x2e\x01\x89\x62" + b"\x0e\xfa\x2f\x43\x42\x11\x30\xfb\x6f\xc0\x2e\x01\x42\xb0\x5f\xc1\x4a\x00\x00" + b"\x6d\x57\x00\x00\x77\x8e\x00\x00\xe0\xff\xff\xff\xd3\xff\xff\xff\xe5\xff\xff" + b"\xff\xee\xe1\xff\xff\x7c\x13\x00\x00\x46\xe6\xff\xff\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x2e\x00\xc1\x80" + b"\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1" + b"\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00" + b"\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e" + b"\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80" + b"\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1" + b"\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00" + b"\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e" + b"\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80" + b"\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1" + b"\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00" + b"\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e" + b"\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80\x2e\x00\xc1\x80" + b"\x2e\x00\xc1" +) + + +class BMI270: + def __init__( + self, + bus, + cs=None, + address=_DEFAULT_ADDR, + gyro_odr=100, + gyro_scale=2000, + accel_odr=100, + accel_scale=4, + bmm_magnet=None, + ): + """Initalizes Gyro and Accelerometer. + bus: IMU bus + address: I2C address (in I2C mode). + cs: SPI CS pin (in SPI mode). + gyro_odr: (0.78, 1.5Hz, 3.1Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 400Hz, 800Hz, 1600Hz) + gyro_scale: (125dps, 250dps, 500dps, 1000dps, 2000dps) + accel_odr: (0.78, 1.5Hz, 3.1Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 400Hz, 800Hz, 1600Hz) + accel_scale: (+/-2g, +/-4g, +/-8g, +-16g) + """ + self.bus = bus + self.bmm_magnet = bmm_magnet + self.cs = cs + self.address = address + self._use_i2c = hasattr(self.bus, "readfrom_mem") + + ACCEL_SCALE = (2, 4, 8, 16) + GYRO_SCALE = (2000, 1000, 500, 250, 125) + ODR = (0.78, 1.5, 3.1, 6.25, 12.5, 25, 50, 100, 200, 400, 800, 1200) + + # Sanity checks + if not self._use_i2c: + raise ValueError("SPI mode is not supported") + if gyro_odr not in ODR: + raise ValueError("Invalid gyro sampling rate: %d" % gyro_odr) + if gyro_scale not in GYRO_SCALE: + raise ValueError("Invalid gyro scaling: %d" % gyro_scale) + if accel_odr not in ODR: + raise ValueError("Invalid accelerometer sampling rate: %d" % accel_odr) + if accel_scale not in ACCEL_SCALE: + raise ValueError("Invalid accelerometer scaling: %d" % accel_scale) + if self._read_reg(_CHIP_ID) != 0x24: + raise OSError("No BMI270 device was found at address 0x%x" % (self.address)) + + # Perform initialization sequence. + # 0. Soft-reset + self._write_reg(_CMD, 0xB6) + time.sleep_ms(250) + + # 1. Disable power save mode. + self._write_reg(0x7C, 0x00) + time.sleep_ms(10) + + # 2. Prepare config load. + self._write_reg(0x59, 0x00) + + # 3. Load config data. + self._write_burst(0x5E, _CONFIG_DATA) + + # 4. Finish config load. + self._write_reg(0x59, 0x01) + + # 5. Check correct initialization status. + if not self._poll_reg(_STATUS, 0x01): + raise OSError("Init sequence failed") + + # 6. Configure the device in normal power mode + # FIFO Reset + self._write_reg(_CMD, 0xB0) + # Enable accel, gyro and temperature data. + self._write_reg(0x7D, 0x0E) + # acc_filter_perf | acc_bwp normal mode | ODR + self._write_reg(0x40, 0xA | (ODR.index(accel_odr) + 1)) + # gyr_filter_perf | gyr_bwp normal mode | ODR + self._write_reg(0x42, 0xA | (ODR.index(gyro_odr) + 1)) + # Disable adv_power_save | Enable fifo_self_wakeup. + self._write_reg(0x7C, 0x02) + + # Set accelerometer scale and range. + self.accel_scale = 32768 / accel_scale + self._write_reg(0x41, ACCEL_SCALE.index(accel_scale)) + + # Set gyroscope scale and range. + self.gyro_scale = 32768 / gyro_scale + self._write_reg(0x43, GYRO_SCALE.index(gyro_scale)) + + # Allocate scratch buffer and set scale. + self.scratch = memoryview(array.array("h", [0, 0, 0])) + + def _read_reg(self, reg, size=1): + buf = self.bus.readfrom_mem(self.address, reg, size) + if size == 1: + return int(buf[0]) + return buf + + def _read_reg_into(self, reg, buf): + self.bus.readfrom_mem_into(self.address, reg, buf) + + def _write_reg(self, reg, val): + if isinstance(val, int): + val = bytes([val]) + self.bus.writeto_mem(self.address, reg, val) + time.sleep_ms(1) + + def _write_burst(self, reg, data, chunk=16): + self._write_reg(_INIT_ADDR_0, 0) + self._write_reg(_INIT_ADDR_1, 0) + for i in range(len(data) // chunk): + offs = i * chunk + self._write_reg(reg, data[offs : offs + chunk]) + init_addr = ((i + 1) * chunk) // 2 + self._write_reg(_INIT_ADDR_0, (init_addr & 0x0F)) + self._write_reg(_INIT_ADDR_1, (init_addr >> 4) & 0xFF) + + def _poll_reg(self, reg, mask, retry=10, delay=100): + for i in range(retry): + if self._read_reg(reg) & mask: + return True + time.sleep_ms(delay) + return False + + def reset(self): + self._write_reg(_CMD, 0xB6) + + def gyro(self): + """Returns gyroscope vector in degrees/sec.""" + f = self.gyro_scale + self._read_reg_into(_DATA_14, self.scratch) + return (self.scratch[0] / f, self.scratch[1] / f, self.scratch[2] / f) + + def accel(self): + """Returns acceleration vector in gravity units (9.81m/s^2).""" + f = self.accel_scale + self._read_reg_into(_DATA_8, self.scratch) + return (self.scratch[0] / f, self.scratch[1] / f, self.scratch[2] / f) + + def magnet(self): + """Returns magnetometer vector.""" + if self.bmm_magnet is not None: + return self.bmm_magnet.magnet() + return (0.0, 0.0, 0.0) diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.pyi b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.pyi new file mode 100644 index 000000000..6ead6dac2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmi270.pyi @@ -0,0 +1,53 @@ +from _typeshed import Incomplete + +_DEFAULT_ADDR: int +_CHIP_ID: int +_STATUS: int +_INIT_ADDR_0: int +_INIT_ADDR_1: int +_DATA_8: int +_DATA_14: int +_CMD: int +_CONFIG_DATA: Incomplete + +class BMI270: + bus: Incomplete + bmm_magnet: Incomplete + cs: Incomplete + address: Incomplete + _use_i2c: Incomplete + accel_scale: Incomplete + gyro_scale: Incomplete + scratch: Incomplete + def __init__( + self, + bus, + cs=None, + address=..., + gyro_odr: int = 100, + gyro_scale: int = 2000, + accel_odr: int = 100, + accel_scale: int = 4, + bmm_magnet=None, + ) -> None: + """Initalizes Gyro and Accelerometer. + bus: IMU bus + address: I2C address (in I2C mode). + cs: SPI CS pin (in SPI mode). + gyro_odr: (0.78, 1.5Hz, 3.1Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 400Hz, 800Hz, 1600Hz) + gyro_scale: (125dps, 250dps, 500dps, 1000dps, 2000dps) + accel_odr: (0.78, 1.5Hz, 3.1Hz, 6.25Hz, 12.5Hz, 25Hz, 50Hz, 100Hz, 200Hz, 400Hz, 800Hz, 1600Hz) + accel_scale: (+/-2g, +/-4g, +/-8g, +-16g) + """ + def _read_reg(self, reg, size: int = 1): ... + def _read_reg_into(self, reg, buf) -> None: ... + def _write_reg(self, reg, val) -> None: ... + def _write_burst(self, reg, data, chunk: int = 16) -> None: ... + def _poll_reg(self, reg, mask, retry: int = 10, delay: int = 100): ... + def reset(self) -> None: ... + def gyro(self): + """Returns gyroscope vector in degrees/sec.""" + def accel(self): + """Returns acceleration vector in gravity units (9.81m/s^2).""" + def magnet(self): + """Returns magnetometer vector.""" diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.py b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.py new file mode 100644 index 000000000..da22a56c2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.py @@ -0,0 +1,184 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Basic example usage: + +import time +from bmm150 import BMM150 +from machine import Pin, SPI, I2C + +# Init in I2C mode. +imu = BMM150(I2C(1, scl=Pin(15), sda=Pin(14))) + +# Or init in SPI mode. +# TODO: Not supported yet. +# imu = BMM150(SPI(5), cs=Pin(10)) + +while (True): + print('magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.magnet())) + time.sleep_ms(100) +""" + +import array +import time +from micropython import const + +_DEFAULT_ADDR = 0x10 +_CHIP_ID = 0x40 +_DATA = 0x42 +_POWER = 0x4B +_OPMODE = 0x4C +_INT_STATUS = 0x4A +_TRIM_X1 = 0x5D +_TRIM_Y1 = 0x5E +_TRIM_Z4_LSB = 0x62 +_TRIM_Z2_LSB = 0x68 +_XYAXES_FLIP = -4096 +_ZHAXES_FLIP = -16384 +_ODR = (10, 2, 6, 8, 15, 20, 25, 30) + + +class BMM150: + def __init__( + self, + bus, + cs=None, + address=_DEFAULT_ADDR, + magnet_odr=30, + ): + """Initalizes the Magnetometer. + bus: IMU bus + address: I2C address (in I2C mode). + cs: SPI CS pin (in SPI mode). + magnet_odr: (2, 6, 8, 10, 15, 20, 25, 30) + """ + self.bus = bus + self.cs = cs + self.address = address + self._use_i2c = hasattr(self.bus, "readfrom_mem") + + # Sanity checks + if not self._use_i2c: + raise ValueError("SPI mode is not supported") + if magnet_odr not in _ODR: + raise ValueError("Invalid sampling rate: %d" % magnet_odr) + + # Perform soft reset, and power on. + self._write_reg(_POWER, 0x83) + time.sleep_ms(10) + + if self._read_reg(_CHIP_ID) != 0x32: + raise OSError("No BMM150 device was found at address 0x%x" % (self.address)) + + # Configure the device. + # ODR | OP: Normal mode + self._write_reg(_OPMODE, _ODR.index(magnet_odr) << 3) + + # Read trim registers. + trim_x1y1 = self._read_reg(_TRIM_X1, 2) + trim_xyz_data = self._read_reg(_TRIM_Z4_LSB, 4) + trim_xy1xy2 = self._read_reg(_TRIM_Z2_LSB, 10) + + self.trim_x1 = trim_x1y1[0] + self.trim_y1 = trim_x1y1[1] + self.trim_x2 = trim_xyz_data[2] + self.trim_y2 = trim_xyz_data[3] + self.trim_z1 = (trim_xy1xy2[3] << 8) | trim_xy1xy2[2] + self.trim_z2 = (trim_xy1xy2[1] << 8) | trim_xy1xy2[0] + self.trim_z3 = (trim_xy1xy2[7] << 8) | trim_xy1xy2[6] + self.trim_z4 = (trim_xyz_data[1] << 8) | trim_xyz_data[0] + self.trim_xy1 = trim_xy1xy2[9] + self.trim_xy2 = trim_xy1xy2[8] + self.trim_xyz1 = ((trim_xy1xy2[5] & 0x7F) << 8) | trim_xy1xy2[4] + + # Allocate scratch buffer. + self.scratch = memoryview(array.array("h", [0, 0, 0, 0])) + + def _read_reg(self, reg, size=1): + buf = self.bus.readfrom_mem(self.address, reg, size) + if size == 1: + return int(buf[0]) + return buf + + def _read_reg_into(self, reg, buf): + self.bus.readfrom_mem_into(self.address, reg, buf) + + def _write_reg(self, reg, val): + self.bus.writeto_mem(self.address, reg, bytes([val])) + + def _compensate_x(self, raw, hall): + """Compensation equation ported from C driver""" + x = 0 + if raw != _XYAXES_FLIP: + x0 = self.trim_xyz1 * 16384 / hall + x = x0 - 16384 + x1 = (self.trim_xy2) * (x**2 / 268435456) + x2 = x1 + x * (self.trim_xy1) / 16384 + x3 = (self.trim_x2) + 160 + x4 = raw * ((x2 + 256) * x3) + x = ((x4 / 8192) + (self.trim_x1 * 8)) / 16 + return x + + def _compensate_y(self, raw, hall): + """Compensation equation ported from C driver""" + y = 0 + if raw != _XYAXES_FLIP: + y0 = self.trim_xyz1 * 16384 / hall + y = y0 - 16384 + y1 = self.trim_xy2 * (y**2 / 268435456) + y2 = y1 + y * self.trim_xy1 / 16384 + y3 = self.trim_y2 + 160 + y4 = raw * ((y2 + 256) * y3) + y = ((y4 / 8192) + (self.trim_y1 * 8)) / 16 + return y + + def _compensate_z(self, raw, hall): + """Compensation equation ported from C driver""" + z = 0 + if raw != _ZHAXES_FLIP: + z0 = raw - self.trim_z4 + z1 = hall - self.trim_xyz1 + z2 = self.trim_z3 * z1 + z3 = (self.trim_z1 * hall) / 32768 + z4 = self.trim_z2 + z3 + z5 = (z0 * 131072) - z2 + z = (z5 / (z4 * 4)) / 16 + return z + + def magnet_raw(self): + for i in range(10): + self._read_reg_into(_DATA, self.scratch) + if self.scratch[3] & 0x1: + return ( + self.scratch[0] >> 3, + self.scratch[1] >> 3, + self.scratch[2] >> 1, + self.scratch[3] >> 2, + ) + time.sleep_ms(30) + raise OSError("Data not ready") + + def magnet(self): + """Returns magnetometer vector.""" + x, y, z, h = self.magnet_raw() + return (self._compensate_x(x, h), self._compensate_y(y, h), self._compensate_z(z, h)) diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.pyi b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.pyi new file mode 100644 index 000000000..2109d21f8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/bmm150.pyi @@ -0,0 +1,53 @@ +from _typeshed import Incomplete +from micropython import const as const + +_DEFAULT_ADDR: int +_CHIP_ID: int +_DATA: int +_POWER: int +_OPMODE: int +_INT_STATUS: int +_TRIM_X1: int +_TRIM_Y1: int +_TRIM_Z4_LSB: int +_TRIM_Z2_LSB: int +_XYAXES_FLIP: int +_ZHAXES_FLIP: int +_ODR: Incomplete + +class BMM150: + bus: Incomplete + cs: Incomplete + address: Incomplete + _use_i2c: Incomplete + trim_x1: Incomplete + trim_y1: Incomplete + trim_x2: Incomplete + trim_y2: Incomplete + trim_z1: Incomplete + trim_z2: Incomplete + trim_z3: Incomplete + trim_z4: Incomplete + trim_xy1: Incomplete + trim_xy2: Incomplete + trim_xyz1: Incomplete + scratch: Incomplete + def __init__(self, bus, cs=None, address=..., magnet_odr: int = 30) -> None: + """Initalizes the Magnetometer. + bus: IMU bus + address: I2C address (in I2C mode). + cs: SPI CS pin (in SPI mode). + magnet_odr: (2, 6, 8, 10, 15, 20, 25, 30) + """ + def _read_reg(self, reg, size: int = 1): ... + def _read_reg_into(self, reg, buf) -> None: ... + def _write_reg(self, reg, val) -> None: ... + def _compensate_x(self, raw, hall): + """Compensation equation ported from C driver""" + def _compensate_y(self, raw, hall): + """Compensation equation ported from C driver""" + def _compensate_z(self, raw, hall): + """Compensation equation ported from C driver""" + def magnet_raw(self): ... + def magnet(self): + """Returns magnetometer vector.""" diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.py b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.py new file mode 100644 index 000000000..003501649 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.py @@ -0,0 +1,64 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +HS3003 driver for MicroPython. + +Example usage: + +import time +from hs3003 import HS3003 +from machine import Pin, I2C + +bus = I2C(1, scl=Pin(15), sda=Pin(14)) +hts = HS3003(bus) + +while True: + rH = hts.humidity() + temp = hts.temperature() + print ("rH: %.2f%% T: %.2fC" %(rH, temp)) + time.sleep_ms(100) +""" + +import struct + + +class HS3003: + def __init__(self, bus, address=0x44): + self.bus = bus + self.address = address + + def _read_data(self): + # Init measurement mode + self.bus.writeto(self.address, b"") + # Data fetch + return struct.unpack(">HH", self.bus.readfrom(self.address, 4)) + + def humidity(self): + """Returns the relative humidity in percent.""" + h, t = self._read_data() + return ((h & 0x3FFF) / 16383) * 100 + + def temperature(self): + """Returns the temperature in degrees Celsius.""" + h, t = self._read_data() + return ((t >> 2) / 16383) * 165 - 40 diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.pyi b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.pyi new file mode 100644 index 000000000..31c9fe524 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hs3003.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete + +class HS3003: + bus: Incomplete + address: Incomplete + def __init__(self, bus, address: int = 68) -> None: ... + def _read_data(self): ... + def humidity(self): + """Returns the relative humidity in percent.""" + def temperature(self): + """Returns the temperature in degrees Celsius.""" diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.py b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.py new file mode 100644 index 000000000..a4188e290 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.py @@ -0,0 +1,89 @@ +""" +The MIT License (MIT) + +Copyright (c) 2013-2022 Ibrahim Abdelkader +Copyright (c) 2013-2022 Kwabena W. Agyeman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +HTS221 driver driver for MicroPython. +Original source: https://github.com/ControlEverythingCommunity/HTS221/blob/master/Python/HTS221.py + +Example usage: + +import time +import hts221 +from machine import Pin, I2C + +bus = I2C(1, scl=Pin(15), sda=Pin(14)) +hts = hts221.HTS221(bus) + +while (True): + rH = hts.humidity() + temp = hts.temperature() + print ("rH: %.2f%% T: %.2fC" %(rH, temp)) + time.sleep_ms(100) +""" + +import struct + + +class HTS221: + def __init__(self, i2c, data_rate=1, address=0x5F): + self.bus = i2c + self.odr = data_rate + self.slv_addr = address + + # Set configuration register + # Humidity and temperature average configuration + self.bus.writeto_mem(self.slv_addr, 0x10, b"\x1b") + + # Set control register + # PD | BDU | ODR + cfg = 0x80 | 0x04 | (self.odr & 0x3) + self.bus.writeto_mem(self.slv_addr, 0x20, bytes([cfg])) + + # Read Calibration values from non-volatile memory of the device + # Humidity Calibration values + self.H0 = self._read_reg(0x30, 1) / 2 + self.H1 = self._read_reg(0x31, 1) / 2 + self.H2 = self._read_reg(0x36, 2) + self.H3 = self._read_reg(0x3A, 2) + + # Temperature Calibration values + raw = self._read_reg(0x35, 1) + self.T0 = ((raw & 0x03) * 256) + self._read_reg(0x32, 1) + self.T1 = ((raw & 0x0C) * 64) + self._read_reg(0x33, 1) + self.T2 = self._read_reg(0x3C, 2) + self.T3 = self._read_reg(0x3E, 2) + + def _read_reg(self, reg_addr, size): + fmt = "B" if size == 1 else "H" + reg_addr = reg_addr if size == 1 else reg_addr | 0x80 + return struct.unpack(fmt, self.bus.readfrom_mem(self.slv_addr, reg_addr, size))[0] + + def humidity(self): + rH = self._read_reg(0x28, 2) + return (self.H1 - self.H0) * (rH - self.H2) / (self.H3 - self.H2) + self.H0 + + def temperature(self): + temp = self._read_reg(0x2A, 2) + if temp > 32767: + temp -= 65536 + return ((self.T1 - self.T0) / 8.0) * (temp - self.T2) / (self.T3 - self.T2) + (self.T0 / 8.0) diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.pyi b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.pyi new file mode 100644 index 000000000..813c61ff2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/hts221.pyi @@ -0,0 +1,18 @@ +from _typeshed import Incomplete + +class HTS221: + bus: Incomplete + odr: Incomplete + slv_addr: Incomplete + H0: Incomplete + H1: Incomplete + H2: Incomplete + H3: Incomplete + T0: Incomplete + T1: Incomplete + T2: Incomplete + T3: Incomplete + def __init__(self, i2c, data_rate: int = 1, address: int = 95) -> None: ... + def _read_reg(self, reg_addr, size): ... + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/imu.py b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/imu.py new file mode 100644 index 000000000..b60fa7301 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/imu.py @@ -0,0 +1,43 @@ +""" +IMU module for Arduino Nano BLE 33 SENSE (REV1 and REV2). + +Example usage: + +import time +import imu +from machine import Pin, I2C + +bus = I2C(1, scl=Pin(15), sda=Pin(14)) +imu = imu.IMU(bus) + +while (True): + print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.accel())) + print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.gyro())) + print('Magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.magnet())) + print("") + time.sleep_ms(100) +""" + + +class IMU: + def __init__(self, bus): + """Initializes Gyro, Accelerometer and Magnetometer using default values.""" + if 0x68 in bus.scan(): + from bmm150 import BMM150 + from bmi270 import BMI270 + + magnet = BMM150(bus) + self.imu = BMI270(bus, bmm_magnet=magnet) + else: + from lsm9ds1 import LSM9DS1 + + self.imu = LSM9DS1(bus) + + def gyro(self): + return self.imu.gyro() + + def accel(self): + return self.imu.accel() + + def magnet(self): + return self.imu.magnet() diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/imu.pyi b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/imu.pyi new file mode 100644 index 000000000..619394f45 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/imu.pyi @@ -0,0 +1,9 @@ +from _typeshed import Incomplete + +class IMU: + imu: Incomplete + def __init__(self, bus) -> None: + """Initializes Gyro, Accelerometer and Magnetometer using default values.""" + def gyro(self): ... + def accel(self): ... + def magnet(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.py b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.py new file mode 100644 index 000000000..84bc17790 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.py @@ -0,0 +1,105 @@ +""" +The MIT License (MIT) + +Copyright (c) 2016-2019 shaoziyang +Copyright (c) 2022 Ibrahim Abdelkader + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +LPS22HB/HH pressure sensor driver for MicroPython. + +Example usage: + +import time +from lps22h import LPS22H +from machine import Pin, I2C + +bus = I2C(1, scl=Pin(15), sda=Pin(14)) +lps = LPS22H(bus, oneshot=False) + +while (True): + print("Pressure: %.2f hPa Temperature: %.2f C"%(lps.pressure(), lps.temperature())) + time.sleep_ms(10) +""" + +import machine +from micropython import const + +_LPS22_CTRL_REG1 = 0x10 +_LPS22_CTRL_REG2 = 0x11 +_LPS22_STATUS = 0x27 +_LPS22_TEMP_OUT_L = 0x2B +_LPS22_PRESS_OUT_XL = 0x28 +_LPS22_PRESS_OUT_L = 0x29 + + +class LPS22H: + def __init__(self, i2c, address=0x5C, oneshot=False): + self.i2c = i2c + self.addr = address + self.oneshot = oneshot + self.buf = bytearray(1) + # ODR=1 EN_LPFP=1 BDU=1 + self._write_reg(_LPS22_CTRL_REG1, 0x1A) + self.set_oneshot_mode(self.oneshot) + + def _int16(self, d): + return d if d < 0x8000 else d - 0x10000 + + def _write_reg(self, reg, dat): + self.buf[0] = dat + self.i2c.writeto_mem(self.addr, reg, self.buf) + + def _read_reg(self, reg, width=8): + self.i2c.readfrom_mem_into(self.addr, reg, self.buf) + val = self.buf[0] + if width == 16: + val |= self._read_reg(reg + 1) << 8 + return val + + def _tigger_oneshot(self, b): + if self.oneshot: + self._write_reg(_LPS22_CTRL_REG2, self._read_reg(_LPS22_CTRL_REG2) | 0x01) + self._read_reg(0x28 + b * 2) + while True: + if self._read_reg(_LPS22_STATUS) & b: + return + machine.idle() + + def set_oneshot_mode(self, oneshot): + self._read_reg(_LPS22_CTRL_REG1) + self.oneshot = oneshot + if oneshot: + self.buf[0] &= 0x0F + else: + self.buf[0] |= 0x10 + self._write_reg(_LPS22_CTRL_REG1, self.buf[0]) + + def pressure(self): + if self.oneshot: + self._tigger_oneshot(1) + return (self._read_reg(_LPS22_PRESS_OUT_XL) + self._read_reg(_LPS22_PRESS_OUT_L, 16) * 256) / 4096 + + def temperature(self): + if self.oneshot: + self._tigger_oneshot(2) + return self._int16(self._read_reg(_LPS22_TEMP_OUT_L, 16)) / 100 + + def altitude(self): + return (((1013.25 / self.pressure()) ** (1 / 5.257)) - 1.0) * (self.temperature() + 273.15) / 0.0065 diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.pyi b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.pyi new file mode 100644 index 000000000..1300bfb0d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lps22h.pyi @@ -0,0 +1,24 @@ +from _typeshed import Incomplete +from micropython import const as const + +_LPS22_CTRL_REG1: int +_LPS22_CTRL_REG2: int +_LPS22_STATUS: int +_LPS22_TEMP_OUT_L: int +_LPS22_PRESS_OUT_XL: int +_LPS22_PRESS_OUT_L: int + +class LPS22H: + i2c: Incomplete + addr: Incomplete + oneshot: Incomplete + buf: Incomplete + def __init__(self, i2c, address: int = 92, oneshot: bool = False) -> None: ... + def _int16(self, d): ... + def _write_reg(self, reg, dat) -> None: ... + def _read_reg(self, reg, width: int = 8): ... + def _tigger_oneshot(self, b) -> None: ... + def set_oneshot_mode(self, oneshot) -> None: ... + def pressure(self): ... + def temperature(self): ... + def altitude(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lsm9ds1.py b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lsm9ds1.py new file mode 100644 index 000000000..6ddc936ec --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/lsm9ds1.py @@ -0,0 +1,201 @@ +""" +The MIT License (MIT) + +Copyright (c) 2013, 2014 Damien P. George +Copyright (c) 2022-2023 Ibrahim Abdelkader + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +LSM9DS1 - 9DOF inertial sensor of STMicro driver for MicroPython. +The sensor contains an accelerometer / gyroscope / magnetometer +Uses the internal FIFO to store up to 16 gyro/accel data, use the iter_accel_gyro generator to access it. + +Example usage: + +import time +from lsm9ds1 import LSM9DS1 +from machine import Pin, I2C + +imu = LSM9DS1(I2C(1, scl=Pin(15), sda=Pin(14))) + +while (True): + #for g,a in imu.iter_accel_gyro(): print(g,a) # using fifo + print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.accel())) + print('Magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.magnet())) + print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.gyro())) + print("") + time.sleep_ms(100) +""" + +import array +from micropython import const + + +_WHO_AM_I = 0xF +_CTRL_REG1_G = 0x10 +_INT_GEN_SRC_G = 0x14 +_OUT_TEMP = 0x15 +_OUT_G = 0x18 +_CTRL_REG4_G = 0x1E +_STATUS_REG = 0x27 +_OUT_XL = 0x28 +_FIFO_CTRL_REG = 0x2E +_FIFO_SRC = 0x2F +_OFFSET_REG_X_M = 0x05 +_CTRL_REG1_M = 0x20 +_OUT_M = 0x28 +_ACCEL_SCALE = (2, 16, 4, 8) +_GYRO_SCALE = (245, 500, 2000) +_MAGNET_SCALE = (4, 8, 12, 16) +_ODR_IMU = (0, 14.9, 59.5, 119, 238, 476, 952) +_ODR_MAGNET = (0.625, 1.25, 2.5, 5, 10, 20, 40, 80) + + +class LSM9DS1: + def __init__( + self, + bus, + address_imu=0x6B, + address_magnet=0x1E, + gyro_odr=952, + gyro_scale=245, + accel_odr=952, + accel_scale=4, + magnet_odr=80, + magnet_scale=4, + ): + """Initalizes Gyro, Accelerometer and Magnetometer. + bus: IMU bus + address_imu: IMU I2C address. + address_magnet: Magnetometer I2C address. + gyro_odr: (0, 14.9Hz, 59.5Hz, 119Hz, 238Hz, 476Hz, 952Hz) + gyro_scale: (245dps, 500dps, 2000dps ) + accel_odr: (0, 14.9Hz, 59.5Hz, 119Hz, 238Hz, 476Hz, 952Hz) + accel_scale: (+/-2g, +/-4g, +/-8g, +-16g) + magnet_odr: (0.625Hz, 1.25Hz, 2.5Hz, 5Hz, 10Hz, 20Hz, 40Hz, 80Hz) + magnet_scale: (+/-4, +/-8, +/-12, +/-16) + """ + self.bus = bus + self.address_imu = address_imu + self.address_magnet = address_magnet + + # Sanity checks + if gyro_odr not in _ODR_IMU: + raise ValueError("Invalid gyro sampling rate: %d" % gyro_odr) + if gyro_scale not in _GYRO_SCALE: + raise ValueError("Invalid gyro scaling: %d" % gyro_scale) + + if accel_odr not in _ODR_IMU: + raise ValueError("Invalid accelerometer sampling rate: %d" % accel_odr) + if accel_scale not in _ACCEL_SCALE: + raise ValueError("Invalid accelerometer scaling: %d" % accel_scale) + + if magnet_odr not in _ODR_MAGNET: + raise ValueError("Invalid magnet sampling rate: %d" % magnet_odr) + if magnet_scale not in _MAGNET_SCALE: + raise ValueError("Invalid magnet scaling: %d" % magnet_scale) + + if (self.magent_id() != b"=") or (self.gyro_id() != b"h"): + raise OSError("Invalid LSM9DS1 device, using address {}/{}".format(address_imu, address_magnet)) + + mv = memoryview(bytearray(6)) + + # Configure Gyroscope. + mv[0] = (_ODR_IMU.index(gyro_odr) << 5) | ((_GYRO_SCALE.index(gyro_scale)) << 3) + mv[1:4] = b"\x00\x00\x00" + self.bus.writeto_mem(self.address_imu, _CTRL_REG1_G, mv[:5]) + + # Configure Accelerometer + mv[0] = 0x38 # ctrl4 - enable x,y,z, outputs, no irq latching, no 4D + mv[1] = 0x38 # ctrl5 - enable all axes, no decimation + # ctrl6 - set scaling and sample rate of accel + mv[2] = (_ODR_IMU.index(accel_odr) << 5) | ((_ACCEL_SCALE.index(accel_scale)) << 3) + mv[3] = 0x00 # ctrl7 - leave at default values + mv[4] = 0x4 # ctrl8 - leave at default values + mv[5] = 0x2 # ctrl9 - FIFO enabled + self.bus.writeto_mem(self.address_imu, _CTRL_REG4_G, mv) + + # fifo: use continous mode (overwrite old data if overflow) + self.bus.writeto_mem(self.address_imu, _FIFO_CTRL_REG, b"\x00") + self.bus.writeto_mem(self.address_imu, _FIFO_CTRL_REG, b"\xc0") + + # Configure Magnetometer + mv[0] = 0x40 | (magnet_odr << 2) # ctrl1: high performance mode + mv[1] = _MAGNET_SCALE.index(magnet_scale) << 5 # ctrl2: scale, normal mode, no reset + mv[2] = 0x00 # ctrl3: continous conversion, no low power, I2C + mv[3] = 0x08 # ctrl4: high performance z-axis + mv[4] = 0x00 # ctr5: no fast read, no block update + self.bus.writeto_mem(self.address_magnet, _CTRL_REG1_M, mv[:5]) + + self.gyro_scale = 32768 / gyro_scale + self.accel_scale = 32768 / accel_scale + self.scale_factor_magnet = 32768 / ((_MAGNET_SCALE.index(magnet_scale) + 1) * 4) + + # Allocate scratch buffer for efficient conversions and memread op's + self.scratch_int = array.array("h", [0, 0, 0]) + + def calibrate_magnet(self, offset): + """ + offset is a magnet vector that will be subtracted by the magnetometer + for each measurement. It is written to the magnetometer's offset register + """ + import struct + + offset = [int(i * self.scale_factor_magnet) for i in offset] + self.bus.writeto_mem(self.address_magnet, _OFFSET_REG_X_M, struct.pack(" None: + """Initalizes Gyro, Accelerometer and Magnetometer. + bus: IMU bus + address_imu: IMU I2C address. + address_magnet: Magnetometer I2C address. + gyro_odr: (0, 14.9Hz, 59.5Hz, 119Hz, 238Hz, 476Hz, 952Hz) + gyro_scale: (245dps, 500dps, 2000dps ) + accel_odr: (0, 14.9Hz, 59.5Hz, 119Hz, 238Hz, 476Hz, 952Hz) + accel_scale: (+/-2g, +/-4g, +/-8g, +-16g) + magnet_odr: (0.625Hz, 1.25Hz, 2.5Hz, 5Hz, 10Hz, 20Hz, 40Hz, 80Hz) + magnet_scale: (+/-4, +/-8, +/-12, +/-16) + """ + def calibrate_magnet(self, offset) -> None: + """ + offset is a magnet vector that will be subtracted by the magnetometer + for each measurement. It is written to the magnetometer's offset register + """ + def gyro_id(self): ... + def magent_id(self): ... + def magnet(self): + """Returns magnetometer vector in gauss. + raw_values: if True, the non-scaled adc values are returned + """ + def gyro(self): + """Returns gyroscope vector in degrees/sec.""" + def accel(self): + """Returns acceleration vector in gravity units (9.81m/s^2).""" + def iter_accel_gyro(self) -> Generator[Incomplete]: + """A generator that returns tuples of (gyro,accelerometer) data from the fifo.""" diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/modules.json b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/modules.json new file mode 100644 index 000000000..f41878465 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/modules.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "nrf", + "platform": "nrf", + "machine": "ARDUINO_NANO_33_BLE_SENSE", + "firmware": "micropython-nrf-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_mkfs.py", + "module": "_mkfs" + }, + { + "file": "bmi270.py", + "module": "bmi270" + }, + { + "file": "bmm150.py", + "module": "bmm150" + }, + { + "file": "hs3003.py", + "module": "hs3003" + }, + { + "file": "hts221.py", + "module": "hts221" + }, + { + "file": "imu.py", + "module": "imu" + }, + { + "file": "lps22h.py", + "module": "lps22h" + }, + { + "file": "lsm9ds1.py", + "module": "lsm9ds1" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/removed.txt b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/ARDUINO_NANO_33_BLE_SENSE/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/_mkfs.py b/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/_mkfs.py new file mode 100644 index 000000000..601f9558e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/_mkfs.py @@ -0,0 +1,23 @@ +import vfs, nrf + +try: + from vfs import VfsLfs1 + + vfs.VfsLfs1.mkfs(nrf.Flash()) +except ImportError: + try: + from vfs import VfsLfs2 + + vfs.VfsLfs2.mkfs(nrf.Flash()) + except ImportError: + try: + from vfs import VfsFat + + vfs.VfsFat.mkfs(nrf.Flash()) + except ImportError: + pass + except OSError as e: + if e.args[0] == 5: # I/O Error + flashbdev_size = (nrf.Flash.ioctl(4, 0) * nrf.Flash.ioctl(5, 0)) // 1024 + print() + print("Is `FS_SIZE=%iK` enough for FAT filesystem?" % flashbdev_size) diff --git a/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/_mkfs.pyi b/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/_mkfs.pyi new file mode 100644 index 000000000..5a34f5f24 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/_mkfs.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete +from vfs import VfsFat as VfsFat, VfsLfs1 as VfsLfs1, VfsLfs2 as VfsLfs2 + +flashbdev_size: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/modules.json new file mode 100644 index 000000000..a8ce719ee --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/modules.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "nrf", + "platform": "nrf", + "machine": "GENERIC", + "firmware": "micropython-nrf-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_mkfs.py", + "module": "_mkfs" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/nrf/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/central.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/client.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/core.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/device.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/security.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/server.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/__init__.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/__init__.py new file mode 100644 index 000000000..80790f0da --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/__init__.py @@ -0,0 +1,32 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from ._decoder import CBORDecoder +from ._decoder import load +from ._decoder import loads + +from ._encoder import CBOREncoder +from ._encoder import dump +from ._encoder import dumps diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/__init__.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/__init__.pyi new file mode 100644 index 000000000..0ef59d019 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/__init__.pyi @@ -0,0 +1,2 @@ +from ._decoder import CBORDecoder as CBORDecoder, load as load, loads as loads +from ._encoder import CBOREncoder as CBOREncoder, dump as dump, dumps as dumps diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_decoder.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_decoder.py new file mode 100644 index 000000000..8434aec26 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_decoder.py @@ -0,0 +1,254 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + + +break_marker = object() + + +class CBORSimpleValue(object): + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + def __init__(self, value): + if value < 0 or value > 255: + raise TypeError("simple value too big") + self.value = value + + def __eq__(self, other): + if isinstance(other, CBORSimpleValue): + return self.value == other.value + elif isinstance(other, int): + return self.value == other + return NotImplemented + + def __repr__(self): + return "CBORSimpleValue({self.value})".format(self=self) + + +def decode_uint(decoder, subtype, allow_indefinite=False): + # Major tag 0 + if subtype < 24: + return subtype + elif subtype == 24: + return struct.unpack(">B", decoder.read(1))[0] + elif subtype == 25: + return struct.unpack(">H", decoder.read(2))[0] + elif subtype == 26: + return struct.unpack(">L", decoder.read(4))[0] + elif subtype == 27: + return struct.unpack(">Q", decoder.read(8))[0] + elif subtype == 31 and allow_indefinite: + return None + else: + raise CBORDecodeError("unknown unsigned integer subtype 0x%x" % subtype) + + +def decode_negint(decoder, subtype): + # Major tag 1 + uint = decode_uint(decoder, subtype) + return -uint - 1 + + +def decode_bytestring(decoder, subtype): + # Major tag 2 + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + buf = bytearray() + while True: + initial_byte = decoder.read(1)[0] + if initial_byte == 255: + return buf + else: + length = decode_uint(decoder, initial_byte & 31) + value = decoder.read(length) + buf.extend(value) + else: + return decoder.read(length) + + +def decode_string(decoder, subtype): + # Major tag 3 + return decode_bytestring(decoder, subtype).decode("utf-8") + + +def decode_array(decoder, subtype): + # Major tag 4 + items = [] + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + value = decoder.decode() + if value is break_marker: + break + else: + items.append(value) + else: + for _ in range(length): + item = decoder.decode() + items.append(item) + return items + + +def decode_map(decoder, subtype): + # Major tag 5 + dictionary = {} + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + key = decoder.decode() + if key is break_marker: + break + else: + value = decoder.decode() + dictionary[key] = value + else: + for _ in range(length): + key = decoder.decode() + value = decoder.decode() + dictionary[key] = value + + return dictionary + + +def decode_special(decoder, subtype): + # Simple value + if subtype < 20: + return CBORSimpleValue(subtype) + + # Major tag 7 + return special_decoders[subtype](decoder) + + +def decode_simple_value(decoder): + return CBORSimpleValue(struct.unpack(">B", decoder.read(1))[0]) + + +def decode_float16(decoder): + decoder.read(2) + raise NotImplementedError # no float16 unpack function + + +def decode_float32(decoder): + return struct.unpack(">f", decoder.read(4))[0] + + +def decode_float64(decoder): + return struct.unpack(">d", decoder.read(8))[0] + + +major_decoders = { + 0: decode_uint, + 1: decode_negint, + 2: decode_bytestring, + 3: decode_string, + 4: decode_array, + 5: decode_map, + 7: decode_special, +} + +special_decoders = { + 20: lambda self: False, + 21: lambda self: True, + 22: lambda self: None, + # 23 is undefined + 24: decode_simple_value, + 25: decode_float16, + 26: decode_float32, + 27: decode_float64, + 31: lambda self: break_marker, +} + + +class CBORDecoder(object): + """ + Deserializes a CBOR encoded byte stream. + """ + + def __init__(self, fp): + self.fp = fp + + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + data = self.fp.read(amount) + if len(data) < amount: + raise CBORDecodeError("premature end of stream (expected to read {} bytes, got {} instead)".format(amount, len(data))) + + return data + + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + try: + initial_byte = self.fp.read(1)[0] + major_type = initial_byte >> 5 + subtype = initial_byte & 31 + except Exception as e: + raise CBORDecodeError("error reading major type at index {}: {}".format(self.fp.tell(), e)) + + decoder = major_decoders[major_type] + try: + return decoder(self, subtype) + except CBORDecodeError: + raise + except Exception as e: + raise CBORDecodeError("error decoding value {}".format(e)) # tell doesn't work on micropython at the moment + + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + fp = io.BytesIO(payload) + return CBORDecoder(fp, **kwargs).decode() + + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + return CBORDecoder(fp, **kwargs).decode() diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_decoder.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_decoder.pyi new file mode 100644 index 000000000..d4daffe85 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_decoder.pyi @@ -0,0 +1,66 @@ +from _typeshed import Incomplete + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + +break_marker: Incomplete + +class CBORSimpleValue: + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + value: Incomplete + def __init__(self, value) -> None: ... + def __eq__(self, other): ... + def __repr__(self) -> str: ... + +def decode_uint(decoder, subtype, allow_indefinite: bool = False): ... +def decode_negint(decoder, subtype): ... +def decode_bytestring(decoder, subtype): ... +def decode_string(decoder, subtype): ... +def decode_array(decoder, subtype): ... +def decode_map(decoder, subtype): ... +def decode_special(decoder, subtype): ... +def decode_simple_value(decoder): ... +def decode_float16(decoder) -> None: ... +def decode_float32(decoder): ... +def decode_float64(decoder): ... + +major_decoders: Incomplete +special_decoders: Incomplete + +class CBORDecoder: + """ + Deserializes a CBOR encoded byte stream. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_encoder.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_encoder.py new file mode 100644 index 000000000..fe8715468 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_encoder.py @@ -0,0 +1,182 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + + +def encode_length(major_tag, length): + if length < 24: + return struct.pack(">B", major_tag | length) + elif length < 256: + return struct.pack(">BB", major_tag | 24, length) + elif length < 65536: + return struct.pack(">BH", major_tag | 25, length) + elif length < 4294967296: + return struct.pack(">BL", major_tag | 26, length) + else: + return struct.pack(">BQ", major_tag | 27, length) + + +def encode_semantic(encoder, tag, value): + encoder.write(encode_length(0xC0, tag)) + encoder.encode(value) + + +def encode_float(encoder, value): + # Handle special values efficiently + import math + + if math.isnan(value): + encoder.write(b"\xf9\x7e\x00") + elif math.isinf(value): + encoder.write(b"\xf9\x7c\x00" if value > 0 else b"\xf9\xfc\x00") + else: + encoder.write(struct.pack(">Bd", 0xFB, value)) + + +def encode_int(encoder, value): + # Big integers (2 ** 64 and over) + if value >= 18446744073709551616 or value < -18446744073709551616: + if value >= 0: + major_type = 0x02 + else: + major_type = 0x03 + value = -value - 1 + + values = [] + while value > 0: + value, remainder = divmod(value, 256) + values.insert(0, remainder) + + payload = bytes(values) + encode_semantic(encoder, major_type, payload) + elif value >= 0: + encoder.write(encode_length(0, value)) + else: + encoder.write(encode_length(0x20, abs(value) - 1)) + + +def encode_bytestring(encoder, value): + encoder.write(encode_length(0x40, len(value)) + value) + + +def encode_bytearray(encoder, value): + encode_bytestring(encoder, bytes(value)) + + +def encode_string(encoder, value): + encoded = value.encode("utf-8") + encoder.write(encode_length(0x60, len(encoded)) + encoded) + + +def encode_map(encoder, value): + encoder.write(encode_length(0xA0, len(value))) + for key, val in value.items(): + encoder.encode(key) + encoder.encode(val) + + +def encode_array(encoder, value): + encoder.write(encode_length(0x80, len(value))) + for item in value: + encoder.encode(item) + + +def encode_boolean(encoder, value): + encoder.write(b"\xf5" if value else b"\xf4") + + +def encode_none(encoder, value): + encoder.write(b"\xf6") + + +cbor_encoders = { # supported data types and the encoder to use. + bytes: encode_bytestring, + bytearray: encode_bytearray, + str: encode_string, + int: encode_int, + float: encode_float, + bool: encode_boolean, + type(None): encode_none, + list: encode_array, + dict: encode_map, +} + + +class CBOREncoder(object): + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + def __init__(self, fp): + self.fp = fp + + def _find_encoder(self, obj): + return cbor_encoders[type(obj)] + + def write(self, data): + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + self.fp.write(data) + + def encode(self, obj): + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + encoder = self._find_encoder(obj) + if not encoder: + raise CBOREncodeError("cannot serialize type %s" % type(obj)) + encoder(self, obj) + + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + fp = io.BytesIO() + dump(obj, fp, **kwargs) + return fp.getvalue() + + +def dump(obj, fp, **kwargs): + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ + CBOREncoder(fp, **kwargs).encode(obj) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_encoder.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_encoder.pyi new file mode 100644 index 000000000..8cd761686 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cbor2/_encoder.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + +def encode_length(major_tag, length): ... +def encode_semantic(encoder, tag, value) -> None: ... +def encode_float(encoder, value) -> None: ... +def encode_int(encoder, value) -> None: ... +def encode_bytestring(encoder, value) -> None: ... +def encode_bytearray(encoder, value) -> None: ... +def encode_string(encoder, value) -> None: ... +def encode_map(encoder, value) -> None: ... +def encode_array(encoder, value) -> None: ... +def encode_boolean(encoder, value) -> None: ... +def encode_none(encoder, value) -> None: ... + +cbor_encoders: Incomplete + +class CBOREncoder: + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def _find_encoder(self, obj): ... + def write(self, data) -> None: + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + def encode(self, obj) -> None: + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + +def dump(obj, fp, **kwargs) -> None: + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.py new file mode 100644 index 000000000..3616db5a7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.py @@ -0,0 +1,357 @@ +# This file is part of the cmwx1 module. +# +# Copyright (c) 2013-2021 Ibrahim Abdelkader +# Copyright (c) 2013-2021 Sebastian Romero +# Copyright (c) 2021 Arduino SA +# +# This work is licensed under the MIT license, see the file LICENSE for details. +# +# CMWX1ZZABZ-093 driver for Arduino boards. +# Note this module runs a stock or a custom Arduino firmware. + +from time import sleep_ms +from time import ticks_ms +from machine import UART +from machine import Pin +from micropython import const + + +class LoraError(Exception): + pass + + +class LoraErrorTimeout(LoraError): + pass + + +class LoraErrorParam(LoraError): + pass + + +class LoraErrorBusy(LoraError): + pass + + +class LoraErrorOverflow(LoraError): + pass + + +class LoraErrorNoNetwork(LoraError): + pass + + +class LoraErrorRX(LoraError): + pass + + +class LoraErrorUnknown(LoraError): + pass + + +class Lora: + MODE_ABP = 0 + MODE_OTAA = 1 + + CLASS_A = "A" + CLASS_B = "B" + CLASS_C = "C" + + BAND_AS923 = 0 + BAND_AU915 = 1 + BAND_EU868 = 5 + BAND_KR920 = 6 + BAND_IN865 = 7 + BAND_US915 = 8 + BAND_US915_HYBRID = 9 + + RF_MODE_RFO = 0 + RF_MODE_PABOOST = 1 + + LoraErrors = { + "": LoraErrorTimeout, # empty buffer + "+ERR": LoraError, + "+ERR_PARAM": LoraErrorParam, + "+ERR_BUSY": LoraErrorBusy, + "+ERR_PARAM_OVERFLOW": LoraErrorOverflow, + "+ERR_NO_NETWORK": LoraErrorNoNetwork, + "+ERR_RX": LoraErrorRX, + "+ERR_UNKNOWN": LoraErrorUnknown, + } + + def __init__( + self, + uart=None, + rst_pin=None, + boot_pin=None, + band=BAND_EU868, # noqa + poll_ms=300000, + debug=False, + ): + self.debug = debug + self.uart = uart + self.rst_pin = rst_pin + self.boot_pin = boot_pin + self.band = band + self.poll_ms = poll_ms + self.last_poll_ms = ticks_ms() + + self.init_modem() + + # Reset module + self.boot_pin.value(0) + self.rst_pin.value(1) + sleep_ms(200) + self.rst_pin.value(0) + sleep_ms(200) + self.rst_pin.value(1) + + # Restart module + self.restart() + + def init_modem(self): + # Arduino Portenta H7 Pin Configuration + if not self.rst_pin: + self.rst_pin = Pin("PC6", Pin.OUT_PP, Pin.PULL_UP, value=1) + if not self.boot_pin: + self.boot_pin = Pin("PG7", Pin.OUT_PP, Pin.PULL_DOWN, value=0) + if not self.uart: + self.uart = UART(8, 19200) + # self.uart = UART(1, 19200) # Use external module + self.uart.init(19200, bits=8, parity=None, stop=2, timeout=250, timeout_char=100) + + def debug_print(self, data): + if self.debug: + print(data) + + def is_arduino_firmware(self): + return "ARD-078" in self.fw_version + + def configure_class(self, _class): + self.send_command("+CLASS=", _class) + + def configure_band(self, band): + self.send_command("+BAND=", band) + if band == self.BAND_EU868 and self.is_arduino_firmware(): + self.send_command("+DUTYCYCLE=", 1) + return True + + def set_baudrate(self, baudrate): + self.send_command("+UART=", baudrate) + + def set_autobaud(self, timeout=10000): + start = ticks_ms() + while (ticks_ms() - start) < timeout: + if self.send_command("", timeout=200, raise_error=False) == "+OK": + sleep_ms(200) + while self.uart.any(): + self.uart.readchar() + return True + return False + + def get_fw_version(self): + dev = self.send_command("+DEV?") + fw_ver = self.send_command("+VER?") + return dev + " " + fw_ver + + def get_device_eui(self): + return self.send_command("+DEVEUI?") + + def factory_default(self): + self.send_command("+FACNEW") + + def restart(self): + if self.set_autobaud() is False: + raise (LoraError("Failed to set autobaud")) + + # Different delimiter as REBOOT response EVENT doesn't end with '\r'. + if self.send_command("+REBOOT", delimiter="+EVENT=0,0", timeout=10000) != "+EVENT=0,0": + raise (LoraError("Failed to reboot module")) + sleep_ms(1000) + self.fw_version = self.get_fw_version() + self.configure_band(self.band) + + def set_rf_power(self, mode, power): + self.send_command("+RFPOWER=", mode, ",", power) + + def set_port(self, port): + self.send_command("+PORT=", port) + + def set_public_network(self, enable): + self.send_command("+NWK=", int(enable)) + + def sleep(self, enable): + self.send_command("+SLEEP=", int(enable)) + + def format(self, hexMode): + self.send_command("+DFORMAT=", int(hexMode)) + + def set_datarate(self, dr): + self.send_command("+DR=", dr) + + def get_datarate(self): + return int(self.send_command("+DR?")) + + def set_adr(self, adr): + self.send_command("+ADR=", int(adr)) + + def get_adr(self): + return int(self.send_command("+ADR?")) + + def get_devaddr(self): + return self.send_command("+DEVADDR?") + + def get_nwk_skey(self): + return self.send_command("+NWKSKEY?") + + def get_appskey(self): + return self.send_command("+APPSKEY?") + + def get_rx2dr(self): + return int(self.send_command("+RX2DR?")) + + def set_rx2dr(self, dr): + self.send_command("+RX2DR=", dr) + + def get_ex2freq(self): + return int(self.send_command("+RX2FQ?")) + + def set_rx2freq(self, freq): + self.send_command("+RX2FQ=", freq) + + def set_fcu(self, fcu): + self.send_command("+FCU=", fcu) + + def get_fcu(self): + return int(self.send_command("+FCU?")) + + def set_fcd(self, fcd): + self.send_command("+FCD=", fcd) + + def get_fcd(self): + return int(self.send_command("+FCD?")) + + def change_mode(self, mode): + self.send_command("+MODE=", mode) + + def join(self, timeout_ms): + if self.send_command("+JOIN", timeout=timeout_ms) != "+ACK": + return False + response = self.receive("\r", timeout=timeout_ms) + return response == "+EVENT=1,1" + + def get_join_status(self): + return int(self.send_command("+NJS?")) == 1 + + def get_max_size(self): + if self.is_arduino_firmware(): + return 64 + return int(self.send_command("+MSIZE?", timeout=2000)) + + def poll(self): + if (ticks_ms() - self.last_poll_ms) > self.poll_ms: + self.last_poll_ms = ticks_ms() + # Triggers a fake write + self.send_data("\0", True) + + def send_data(self, buff, confirmed=True): + max_len = self.get_max_size() + if len(buff) > max_len: + raise (LoraError("Packet exceeds max length")) + if self.send_command("+CTX " if confirmed else "+UTX ", len(buff), data=buff) != "+OK": + return False + if confirmed: + response = self.receive("\r", timeout=10000) + return response == "+ACK" + return True + + def receive_data(self, timeout=1000): + response = self.receive("\r", timeout=timeout) + if response.startswith("+RECV"): + params = response.split("=")[1].split(",") + port = params[0] + length = int(params[1]) + dummy_data_length = 2 # Data starts with \n\n sequence + data = self.receive(max_bytes=length + dummy_data_length, timeout=timeout)[dummy_data_length:] + return {"port": port, "data": data} + + def receive(self, delimiter=None, max_bytes=None, timeout=1000): + buf = [] + start = ticks_ms() + while (ticks_ms() - start) < timeout: + while self.uart.any(): + buf += chr(self.uart.readchar()) + + if max_bytes and len(buf) == max_bytes: + data = "".join(buf) + self.debug_print(data) + return data + if len(buf) and delimiter is not None: + data = "".join(buf) + trimmed = data[0:-1] if data[-1] == "\r" else data + + if isinstance(delimiter, str) and len(delimiter) == 1 and buf[-1] == delimiter: + self.debug_print(trimmed) + return trimmed + if isinstance(delimiter, str) and trimmed == delimiter: + self.debug_print(trimmed) + return trimmed + if isinstance(delimiter, list) and trimmed in delimiter: + self.debug_print(trimmed) + return trimmed + + data = "".join(buf) + self.debug_print(data) + return data[0:-1] if len(data) != 0 and data[-1] == "\r" else data + + def available(self): + return self.uart.any() + + def join_OTAA(self, appEui, appKey, devEui=None, timeout=60000): + self.change_mode(self.MODE_OTAA) + self.send_command("+APPEUI=", appEui) + self.send_command("+APPKEY=", appKey) + if devEui: + self.send_command("+DEVEUI=", devEui) + network_joined = self.join(timeout) + # This delay was in MKRWAN.h + # delay(1000); + return network_joined + + def join_ABP(self, nwkId, devAddr, nwkSKey, appSKey, timeout=60000): + self.change_mode(self.MODE_ABP) + # Commented in MKRWAN.h + # self.send_command("+IDNWK=", nwkId) + self.send_command("+DEVADDR=", devAddr) + self.send_command("+NWKSKEY=", nwkSKey) + self.send_command("+APPSKEY=", appSKey) + self.join(timeout) + return self.get_join_status() + + def handle_error(self, command, data): + if not data.startswith("+ERR") and data != "": + return + if data in self.LoraErrors: + raise (self.LoraErrors[data]('Command "%s" has failed!' % command)) + raise (LoraError('Command: "%s" failed with unknown status: "%s"' % (command, data))) + + def send_command(self, cmd, *args, delimiter="\r", data=None, timeout=1000, raise_error=True): + # Write command and args + uart_cmd = "AT" + cmd + "".join([str(x) for x in args]) + "\r" + self.debug_print(uart_cmd) + self.uart.write(uart_cmd) + + # Attach raw data + if data: + self.debug_print(data) + self.uart.write(data) + + # Read status and value (if any) + response = self.receive(delimiter, timeout=timeout) + + # Error handling + if raise_error: + self.handle_error(cmd, response) + + if cmd.endswith("?"): + return response.split("=")[1] + return response diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.pyi new file mode 100644 index 000000000..82d9651c4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/cmwx1.pyi @@ -0,0 +1,81 @@ +from _typeshed import Incomplete +from micropython import const as const + +class LoraError(Exception): ... +class LoraErrorTimeout(LoraError): ... +class LoraErrorParam(LoraError): ... +class LoraErrorBusy(LoraError): ... +class LoraErrorOverflow(LoraError): ... +class LoraErrorNoNetwork(LoraError): ... +class LoraErrorRX(LoraError): ... +class LoraErrorUnknown(LoraError): ... + +class Lora: + MODE_ABP: int + MODE_OTAA: int + CLASS_A: str + CLASS_B: str + CLASS_C: str + BAND_AS923: int + BAND_AU915: int + BAND_EU868: int + BAND_KR920: int + BAND_IN865: int + BAND_US915: int + BAND_US915_HYBRID: int + RF_MODE_RFO: int + RF_MODE_PABOOST: int + LoraErrors: Incomplete + debug: Incomplete + uart: Incomplete + rst_pin: Incomplete + boot_pin: Incomplete + band: Incomplete + poll_ms: Incomplete + last_poll_ms: Incomplete + def __init__(self, uart=None, rst_pin=None, boot_pin=None, band=..., poll_ms: int = 300000, debug: bool = False) -> None: ... + def init_modem(self) -> None: ... + def debug_print(self, data) -> None: ... + def is_arduino_firmware(self): ... + def configure_class(self, _class) -> None: ... + def configure_band(self, band): ... + def set_baudrate(self, baudrate) -> None: ... + def set_autobaud(self, timeout: int = 10000): ... + def get_fw_version(self): ... + def get_device_eui(self): ... + def factory_default(self) -> None: ... + fw_version: Incomplete + def restart(self) -> None: ... + def set_rf_power(self, mode, power) -> None: ... + def set_port(self, port) -> None: ... + def set_public_network(self, enable) -> None: ... + def sleep(self, enable) -> None: ... + def format(self, hexMode) -> None: ... + def set_datarate(self, dr) -> None: ... + def get_datarate(self): ... + def set_adr(self, adr) -> None: ... + def get_adr(self): ... + def get_devaddr(self): ... + def get_nwk_skey(self): ... + def get_appskey(self): ... + def get_rx2dr(self): ... + def set_rx2dr(self, dr) -> None: ... + def get_ex2freq(self): ... + def set_rx2freq(self, freq) -> None: ... + def set_fcu(self, fcu) -> None: ... + def get_fcu(self): ... + def set_fcd(self, fcd) -> None: ... + def get_fcd(self): ... + def change_mode(self, mode) -> None: ... + def join(self, timeout_ms): ... + def get_join_status(self): ... + def get_max_size(self): ... + def poll(self) -> None: ... + def send_data(self, buff, confirmed: bool = True): ... + def receive_data(self, timeout: int = 1000): ... + def receive(self, delimiter=None, max_bytes=None, timeout: int = 1000): ... + def available(self): ... + def join_OTAA(self, appEui, appKey, devEui=None, timeout: int = 60000): ... + def join_ABP(self, nwkId, devAddr, nwkSKey, appSKey, timeout: int = 60000): ... + def handle_error(self, command, data) -> None: ... + def send_command(self, cmd, *args, delimiter: str = "\r", data=None, timeout: int = 1000, raise_error: bool = True): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/dht.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/dht.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/logging.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/logging.py new file mode 100644 index 000000000..edee407c6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/logging.py @@ -0,0 +1,253 @@ +from micropython import const +import io +import sys +import time + +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 + +_DEFAULT_LEVEL = WARNING + +_level_dict = { + CRITICAL: "CRITICAL", + ERROR: "ERROR", + WARNING: "WARNING", + INFO: "INFO", + DEBUG: "DEBUG", + NOTSET: "NOTSET", +} + +_loggers = {} +_stream = sys.stderr +_default_fmt = "%(levelname)s:%(name)s:%(message)s" +_default_datefmt = "%Y-%m-%d %H:%M:%S" + + +class LogRecord: + def set(self, name, level, message): + self.name = name + self.levelno = level + self.levelname = _level_dict[level] + self.message = message + self.ct = time.time() + self.msecs = int((self.ct - int(self.ct)) * 1000) + self.asctime = None + + +class Handler: + def __init__(self, level=NOTSET): + self.level = level + self.formatter = None + + def close(self): + pass + + def setLevel(self, level): + self.level = level + + def setFormatter(self, formatter): + self.formatter = formatter + + def format(self, record): + return self.formatter.format(record) + + +class StreamHandler(Handler): + def __init__(self, stream=None): + super().__init__() + self.stream = _stream if stream is None else stream + self.terminator = "\n" + + def close(self): + if hasattr(self.stream, "flush"): + self.stream.flush() + + def emit(self, record): + if record.levelno >= self.level: + self.stream.write(self.format(record) + self.terminator) + + +class FileHandler(StreamHandler): + def __init__(self, filename, mode="a", encoding="UTF-8"): + super().__init__(stream=open(filename, mode=mode, encoding=encoding)) + + def close(self): + super().close() + self.stream.close() + + +class Formatter: + def __init__(self, fmt=None, datefmt=None): + self.fmt = _default_fmt if fmt is None else fmt + self.datefmt = _default_datefmt if datefmt is None else datefmt + + def usesTime(self): + return "asctime" in self.fmt + + def formatTime(self, datefmt, record): + if hasattr(time, "strftime"): + return time.strftime(datefmt, time.localtime(record.ct)) + return None + + def format(self, record): + if self.usesTime(): + record.asctime = self.formatTime(self.datefmt, record) + return self.fmt % { + "name": record.name, + "message": record.message, + "msecs": record.msecs, + "asctime": record.asctime, + "levelname": record.levelname, + } + + +class Logger: + def __init__(self, name, level=NOTSET): + self.name = name + self.level = level + self.handlers = [] + self.record = LogRecord() + + def setLevel(self, level): + self.level = level + + def isEnabledFor(self, level): + return level >= self.getEffectiveLevel() + + def getEffectiveLevel(self): + return self.level or getLogger().level or _DEFAULT_LEVEL + + def log(self, level, msg, *args): + if self.isEnabledFor(level): + if args: + if isinstance(args[0], dict): + args = args[0] + msg = msg % args + self.record.set(self.name, level, msg) + handlers = self.handlers + if not handlers: + handlers = getLogger().handlers + for h in handlers: + h.emit(self.record) + + def debug(self, msg, *args): + self.log(DEBUG, msg, *args) + + def info(self, msg, *args): + self.log(INFO, msg, *args) + + def warning(self, msg, *args): + self.log(WARNING, msg, *args) + + def error(self, msg, *args): + self.log(ERROR, msg, *args) + + def critical(self, msg, *args): + self.log(CRITICAL, msg, *args) + + def exception(self, msg, *args, exc_info=True): + self.log(ERROR, msg, *args) + tb = None + if isinstance(exc_info, BaseException): + tb = exc_info + elif hasattr(sys, "exc_info"): + tb = sys.exc_info()[1] + if tb: + buf = io.StringIO() + sys.print_exception(tb, buf) + self.log(ERROR, buf.getvalue()) + + def addHandler(self, handler): + self.handlers.append(handler) + + def hasHandlers(self): + return len(self.handlers) > 0 + + +def getLogger(name=None): + if name is None: + name = "root" + if name not in _loggers: + _loggers[name] = Logger(name) + if name == "root": + basicConfig() + return _loggers[name] + + +def log(level, msg, *args): + getLogger().log(level, msg, *args) + + +def debug(msg, *args): + getLogger().debug(msg, *args) + + +def info(msg, *args): + getLogger().info(msg, *args) + + +def warning(msg, *args): + getLogger().warning(msg, *args) + + +def error(msg, *args): + getLogger().error(msg, *args) + + +def critical(msg, *args): + getLogger().critical(msg, *args) + + +def exception(msg, *args, exc_info=True): + getLogger().exception(msg, *args, exc_info=exc_info) + + +def shutdown(): + for k, logger in _loggers.items(): + for h in logger.handlers: + h.close() + _loggers.pop(logger, None) + + +def addLevelName(level, name): + _level_dict[level] = name + + +def basicConfig( + filename=None, + filemode="a", + format=None, + datefmt=None, + level=WARNING, + stream=None, + encoding="UTF-8", + force=False, +): + if "root" not in _loggers: + _loggers["root"] = Logger("root") + + logger = _loggers["root"] + + if force or not logger.handlers: + for h in logger.handlers: + h.close() + logger.handlers = [] + + if filename is None: + handler = StreamHandler(stream) + else: + handler = FileHandler(filename, filemode, encoding) + + handler.setLevel(level) + handler.setFormatter(Formatter(format, datefmt)) + + logger.setLevel(level) + logger.addHandler(handler) + + +if hasattr(sys, "atexit"): + sys.atexit(shutdown) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/logging.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/logging.pyi new file mode 100644 index 000000000..856bcccf7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/logging.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete +from micropython import const as const + +CRITICAL: int +ERROR: int +WARNING: int +INFO: int +DEBUG: int +NOTSET: int +_DEFAULT_LEVEL = WARNING +_level_dict: Incomplete +_loggers: Incomplete +_stream: Incomplete +_default_fmt: str +_default_datefmt: str + +class LogRecord: + name: Incomplete + levelno: Incomplete + levelname: Incomplete + message: Incomplete + ct: Incomplete + msecs: Incomplete + asctime: Incomplete + def set(self, name, level, message) -> None: ... + +class Handler: + level: Incomplete + formatter: Incomplete + def __init__(self, level=...) -> None: ... + def close(self) -> None: ... + def setLevel(self, level) -> None: ... + def setFormatter(self, formatter) -> None: ... + def format(self, record): ... + +class StreamHandler(Handler): + stream: Incomplete + terminator: str + def __init__(self, stream=None) -> None: ... + def close(self) -> None: ... + def emit(self, record) -> None: ... + +class FileHandler(StreamHandler): + def __init__(self, filename, mode: str = "a", encoding: str = "UTF-8") -> None: ... + def close(self) -> None: ... + +class Formatter: + fmt: Incomplete + datefmt: Incomplete + def __init__(self, fmt=None, datefmt=None) -> None: ... + def usesTime(self): ... + def formatTime(self, datefmt, record): ... + def format(self, record): ... + +class Logger: + name: Incomplete + level: Incomplete + handlers: Incomplete + record: Incomplete + def __init__(self, name, level=...) -> None: ... + def setLevel(self, level) -> None: ... + def isEnabledFor(self, level): ... + def getEffectiveLevel(self): ... + def log(self, level, msg, *args) -> None: ... + def debug(self, msg, *args) -> None: ... + def info(self, msg, *args) -> None: ... + def warning(self, msg, *args) -> None: ... + def error(self, msg, *args) -> None: ... + def critical(self, msg, *args) -> None: ... + def exception(self, msg, *args, exc_info: bool = True) -> None: ... + def addHandler(self, handler) -> None: ... + def hasHandlers(self): ... + +def getLogger(name=None): ... +def log(level, msg, *args) -> None: ... +def debug(msg, *args) -> None: ... +def info(msg, *args) -> None: ... +def warning(msg, *args) -> None: ... +def error(msg, *args) -> None: ... +def critical(msg, *args) -> None: ... +def exception(msg, *args, exc_info: bool = True) -> None: ... +def shutdown() -> None: ... +def addLevelName(level, name) -> None: ... +def basicConfig( + filename=None, filemode: str = "a", format=None, datefmt=None, level=..., stream=None, encoding: str = "UTF-8", force: bool = False +) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/modules.json b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/modules.json new file mode 100644 index 000000000..2b2f5a191 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/modules.json @@ -0,0 +1,136 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "renesas-ra", + "platform": "renesas-ra", + "machine": "ARDUINO_PORTENTA_C33", + "firmware": "micropython-renesas-ra-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "cbor2/__init__.py", + "module": "__init__" + }, + { + "file": "cbor2/_decoder.py", + "module": "_decoder" + }, + { + "file": "cbor2/_encoder.py", + "module": "_encoder" + }, + { + "file": "cmwx1.py", + "module": "cmwx1" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "logging.py", + "module": "logging" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "senml/__init__.py", + "module": "__init__" + }, + { + "file": "senml/senml_base.py", + "module": "senml_base" + }, + { + "file": "senml/senml_pack.py", + "module": "senml_pack" + }, + { + "file": "senml/senml_record.py", + "module": "senml_record" + }, + { + "file": "senml/senml_unit.py", + "module": "senml_unit" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "time.py", + "module": "time" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ntptime.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/onewire.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/onewire.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/removed.txt b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/__init__.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/__init__.py new file mode 100644 index 000000000..908375fdb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/__init__.py @@ -0,0 +1,29 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from .senml_base import SenmlBase +from .senml_pack import SenmlPack +from .senml_record import SenmlRecord +from .senml_unit import SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/__init__.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/__init__.pyi new file mode 100644 index 000000000..c72285dc4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/__init__.pyi @@ -0,0 +1,4 @@ +from .senml_base import SenmlBase as SenmlBase +from .senml_pack import SenmlPack as SenmlPack +from .senml_record import SenmlRecord as SenmlRecord +from .senml_unit import SenmlUnits as SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_base.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_base.py new file mode 100644 index 000000000..b277c9477 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_base.py @@ -0,0 +1,30 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +class SenmlBase(object): + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_base.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_base.pyi new file mode 100644 index 000000000..240f185ce --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_base.pyi @@ -0,0 +1,4 @@ +class SenmlBase: + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_pack.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_pack.py new file mode 100644 index 000000000..5a0554467 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_pack.py @@ -0,0 +1,358 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from senml.senml_record import SenmlRecord +from senml.senml_base import SenmlBase +import json +import cbor2 + + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + def __init__(self, list): + self._list = list + self._index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self._index < len(self._list): + res = self._list[self._index] + self._index += 1 + return res + else: + raise StopIteration + + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings = { + "bn": "bn", + "bt": "bt", + "bu": "bu", + "bv": "bv", + "bs": "bs", + "n": "n", + "u": "u", + "v": "v", + "vs": "vs", + "vb": "vb", + "vd": "vd", + "s": "s", + "t": "t", + "ut": "ut", + } + + def __init__(self, name, callback=None): + """ + initialize the object + :param name: {string} the name of the pack + """ + self._data = [] + self.name = name + self._base_value = None + self._base_time = None + self._base_sum = None + self.base_unit = None + self._parent = None # a pack can also be the child of another pack. + self.actuate = callback # actuate callback function + + def __iter__(self): + return SenmlPackIterator(self._data) + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + return self._base_value + + @base_value.setter + def base_value(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_value") + self._base_value = value + + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + return self._base_sum + + @base_sum.setter + def base_sum(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_sum") + self._base_sum = value + + @property + def base_time(self): + return self._base_time + + @base_time.setter + def base_time(self, value): + self._check_value_type(value, "base_time") + self._base_time = value + + def _check_value_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + def from_json(self, data): + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + records = json.loads(data) # load the raw senml data + self._process_incomming_data(records, SenmlPack.json_mappings) + + def _process_incomming_data(self, records, naming_map): + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + cur_pack_el = self + new_pack = False + for item in records: + if naming_map["bn"] in item: # ref to a pack element, either this or a child pack. + if item[naming_map["bn"]] != self.name: + pack_el = [x for x in self._data if x.name == item[naming_map["bn"]]] + else: + pack_el = [self] + if len(pack_el) > 0: + cur_pack_el = pack_el[0] + new_pack = False + else: + device = SenmlPack(item[naming_map["bn"]]) + self._data.append(device) + cur_pack_el = device + new_pack = True + + if ( + naming_map["bv"] in item + ): # need to copy the base value assigned to the pack element so we can do proper conversion for actuators. + cur_pack_el.base_value = item[naming_map["bv"]] + + rec_el = [x for x in cur_pack_el._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + else: + rec_el = [x for x in self._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + + def do_actuate(self, raw, naming_map, device=None): + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + rec = SenmlRecord(raw[naming_map["n"]]) + if device: + device.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=device) + else: + self.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=None) + + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + converted = [] + self._build_rec_dict(SenmlPack.json_mappings, converted) + return json.dumps(converted) + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + internalList = [] + for item in self._data: + item._build_rec_dict(naming_map, internalList) + if len(internalList) > 0: + first_rec = internalList[0] + else: + first_rec = {} + internalList.append(first_rec) + + if self.name: + first_rec[naming_map["bn"]] = self.name + if self.base_value: + first_rec[naming_map["bv"]] = self.base_value + if self.base_unit: + first_rec[naming_map["bu"]] = self.base_unit + if self.base_sum: + first_rec[naming_map["bs"]] = self.base_sum + if self.base_time: + first_rec[naming_map["bt"]] = self.base_time + appendTo.extend(internalList) + + def from_cbor(self, data): + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + records = cbor2.loads(data) # load the raw senml data + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + self._process_incomming_data(records, naming_map) + + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + converted = [] + self._build_rec_dict(naming_map, converted) + return cbor2.dumps(converted) + + def add(self, item): + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if item._parent is not None: + raise Exception("item is already part of a pack") + + self._data.append(item) + item._parent = self + + def remove(self, item): + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if not item._parent == self: + raise Exception("item is not part of this pack") + + self._data.remove(item) + item._parent = None + + def clear(self): + """ + clear the list of the pack + :return: None + """ + for item in self._data: + item._parent = None + self._data = [] diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_pack.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_pack.pyi new file mode 100644 index 000000000..57a0cf547 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_pack.pyi @@ -0,0 +1,143 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase +from senml.senml_record import SenmlRecord as SenmlRecord + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + _list: Incomplete + _index: int + def __init__(self, list) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings: Incomplete + _data: Incomplete + name: Incomplete + _base_value: Incomplete + _base_time: Incomplete + _base_sum: Incomplete + base_unit: Incomplete + _parent: Incomplete + actuate: Incomplete + def __init__(self, name, callback=None) -> None: + """ + initialize the object + :param name: {string} the name of the pack + """ + def __iter__(self): ... + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + @base_value.setter + def base_value(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + @base_sum.setter + def base_sum(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_time(self): ... + @base_time.setter + def base_time(self, value) -> None: ... + def _check_value_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def from_json(self, data) -> None: + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + def _process_incomming_data(self, records, naming_map) -> None: + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + def do_actuate(self, raw, naming_map, device=None) -> None: + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + def from_cbor(self, data) -> None: + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + def add(self, item) -> None: + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + def remove(self, item) -> None: + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + def clear(self) -> None: + """ + clear the list of the pack + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_record.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_record.py new file mode 100644 index 000000000..b5b07b0bc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_record.py @@ -0,0 +1,240 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import binascii +from senml.senml_base import SenmlBase + + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + def __init__(self, name, **kwargs): + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + self.__parent = None # using double __ cause it's a field for an internal property + self._unit = None # declare and init internal fields + self._value = None + self._time = None + self._sum = None + self._update_time = None + + self._parent = None # internal reference to the parent object + self.name = name + self.unit = kwargs.get("unit", None) + self.value = kwargs.get("value", None) + self.time = kwargs.get("time", None) + self.sum = kwargs.get("sum", None) + self.update_time = kwargs.get("update_time", None) + self.actuate = kwargs.get("callback", None) # actuate callback function + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + def _check_value_type(self, value): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not ( + isinstance(value, bool) + or isinstance(value, int) + or isinstance(value, float) + or isinstance(value, bytearray) + or isinstance(value, str) + ): + raise Exception("invalid type for value, only numbers, strings, boolean and byte arrays allowed") + + def _check_number_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + @property + def value(self): + """get the value currently assigned to the object""" + return self._value + + @value.setter + def value(self, value): + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + self._check_value_type(value) + self._value = value + + @property + def time(self): + return self._time + + @time.setter + def time(self, value): + self._check_number_type(value, "time") + self._time = value + + @property + def update_time(self): + return self._update_time + + @update_time.setter + def update_time(self, value): + self._check_number_type(value, "update_time") + self._update_time = value + + @property + def sum(self): + return self._sum + + @sum.setter + def sum(self, value): + self._check_number_type(value, "sum") + self._sum = value + + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + return self.__parent + + @_parent.setter + def _parent(self, value): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + self.__parent = value + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + result = {} + + if self.name: + result[naming_map["n"]] = self.name + + if self._sum: + if self._parent and self._parent.base_sum: + result[naming_map["s"]] = self._sum - self._parent.base_sum + else: + result[naming_map["s"]] = self._sum + elif isinstance(self._value, bool): + result[naming_map["vb"]] = self._value + elif isinstance(self._value, int) or isinstance(self._value, float): + if self._parent and self._parent.base_value: + result[naming_map["v"]] = self._value - self._parent.base_value + else: + result[naming_map["v"]] = self._value + elif isinstance(self._value, str): + result[naming_map["vs"]] = self._value + elif isinstance(self._value, bytearray): + if naming_map["vd"] == "vd": # neeed to make a distinction between json (needs base64) and cbor (needs binary) + result[naming_map["vd"]] = binascii.b2a_base64(self._value, newline=False).decode("utf8") + else: + result[naming_map["vd"]] = self._value + else: + raise Exception("sum or value of type bootl, number, string or byte-array is required") + + if self._time: + if self._parent and self._parent.base_time: + result[naming_map["t"]] = self._time - self._parent.base_time + else: + result[naming_map["t"]] = self._time + + if self.unit: + result[naming_map["u"]] = self.unit + + if self._update_time: + if self._parent and self._parent.base_time: + result[naming_map["ut"]] = self._update_time - self._parent.base_time + else: + result[naming_map["ut"]] = self._update_time + + appendTo.append(result) + + def _from_raw(self, raw, naming_map): + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + if naming_map["v"] in raw: + val = raw[naming_map["v"]] + if self._parent and self._parent.base_value: + val += self._parent.base_value + elif naming_map["vs"] in raw: + val = raw[naming_map["vs"]] + elif naming_map["vb"] in raw: + val = raw[naming_map["vb"]] + elif naming_map["vd"] in raw: + val = binascii.a2b_base64(raw[naming_map["vb"]]) + else: + val = None + self.value = val + + def do_actuate(self, raw, naming_map): + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ + self._from_raw(raw, naming_map) + if self.actuate: + self.actuate(self) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_record.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_record.pyi new file mode 100644 index 000000000..61c0c7c05 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_record.pyi @@ -0,0 +1,104 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + __parent: Incomplete + _unit: Incomplete + _value: Incomplete + _time: Incomplete + _sum: Incomplete + _update_time: Incomplete + name: Incomplete + unit: Incomplete + actuate: Incomplete + def __init__(self, name, **kwargs) -> None: + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + def _check_value_type(self, value) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def _check_number_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + @property + def value(self): + """get the value currently assigned to the object""" + @value.setter + def value(self, value) -> None: + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + @property + def time(self): ... + @time.setter + def time(self, value) -> None: ... + @property + def update_time(self): ... + @update_time.setter + def update_time(self, value) -> None: ... + @property + def sum(self): ... + @sum.setter + def sum(self, value) -> None: ... + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + @_parent.setter + def _parent(self, value) -> None: + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + def _from_raw(self, raw, naming_map) -> None: + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + def do_actuate(self, raw, naming_map) -> None: + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_unit.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_unit.py new file mode 100644 index 000000000..bf7753c4d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_unit.py @@ -0,0 +1,89 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +def enum(**enums): + return type("Enum", (), enums) + + +SenmlUnits = enum( + SENML_UNIT_METER="m", + SENML_UNIT_KILOGRAM="kg", + SENML_UNIT_GRAM="g", + SENML_UNIT_SECOND="s", + SENML_UNIT_AMPERE="A", + SENML_UNIT_KELVIN="K", + SENML_UNIT_CANDELA="cd", + SENML_UNIT_MOLE="mol", + SENML_UNIT_HERTZ="Hz", + SENML_UNIT_RADIAN="rad", + SENML_UNIT_STERADIAN="sr", + SENML_UNIT_NEWTON="N", + SENML_UNIT_PASCAL="Pa", + SENML_UNIT_JOULE="J", + SENML_UNIT_WATT="W", + SENML_UNIT_COULOMB="C", + SENML_UNIT_VOLT="V", + SENML_UNIT_FARAD="F", + SENML_UNIT_OHM="Ohm", + SENML_UNIT_SIEMENS="S", + SENML_UNIT_WEBER="Wb", + SENML_UNIT_TESLA="T", + SENML_UNIT_HENRY="H", + SENML_UNIT_DEGREES_CELSIUS="Cel", + SENML_UNIT_LUMEN="lm", + SENML_UNIT_LUX="lx", + SENML_UNIT_BECQUEREL="Bq", + SENML_UNIT_GRAY="Gy", + SENML_UNIT_SIEVERT="Sv", + SENML_UNIT_KATAL="kat", + SENML_UNIT_SQUARE_METER="m2", + SENML_UNIT_CUBIC_METER="m3", + SENML_UNIT_LITER="l", + SENML_UNIT_VELOCITY="m/s", + SENML_UNIT_ACCELERATION="m/s2", + SENML_UNIT_CUBIC_METER_PER_SECOND="m3/s", + SENML_UNIT_LITER_PER_SECOND="l/s", + SENML_UNIT_WATT_PER_SQUARE_METER="W/m2", + SENML_UNIT_CANDELA_PER_SQUARE_METER="cd/m2", + SENML_UNIT_BIT="bit", + SENML_UNIT_BIT_PER_SECOND="bit/s", + SENML_UNIT_DEGREES_LATITUDE="lat", + SENML_UNIT_DEGREES_LONGITUDE="lon", + SENML_UNIT_PH="pH", + SENML_UNIT_DECIBEL="db", + SENML_UNIT_DECIBEL_RELATIVE_TO_1_W="dBW", + SENML_UNIT_BEL="Bspl", + SENML_UNIT_COUNTER="count", + SENML_UNIT_RATIO="//", + SENML_UNIT_RELATIVE_HUMIDITY="%RH", + SENML_UNIT_PERCENTAGE_REMAINING_BATTERY_LEVEL="%EL", + SENML_UNIT_SECONDS_REMAINING_BATTERY_LEVEL="EL", + SENML_UNIT_EVENT_RATE_PER_SECOND="1/s", + SENML_UNIT_EVENT_RATE_PER_MINUTE="1/min", + SENML_UNIT_BPM="beat/min", + SENML_UNIT_BEATS="beats", + SENML_UNIT_SIEMENS_PER_METER="S/m", +) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_unit.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_unit.pyi new file mode 100644 index 000000000..6b3e7ae68 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/senml/senml_unit.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +def enum(**enums): ... + +SenmlUnits: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ssl.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ssl.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/time.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/time.py new file mode 100644 index 000000000..f79ab8a3b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/time.py @@ -0,0 +1,79 @@ +from utime import * +from micropython import const + +_TS_YEAR = 0 +_TS_MON = 1 +_TS_MDAY = 2 +_TS_HOUR = 3 +_TS_MIN = 4 +_TS_SEC = 5 +_TS_WDAY = 6 +_TS_YDAY = 7 +_TS_ISDST = 8 + +_WDAY = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") +_MDAY = const( + ( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ) +) + + +def strftime(datefmt, ts): + from io import StringIO + + fmtsp = False + ftime = StringIO() + for k in datefmt: + if fmtsp: + if k == "a": + ftime.write(_WDAY[ts[_TS_WDAY]][0:3]) + elif k == "A": + ftime.write(_WDAY[ts[_TS_WDAY]]) + elif k == "b": + ftime.write(_MDAY[ts[_TS_MON] - 1][0:3]) + elif k == "B": + ftime.write(_MDAY[ts[_TS_MON] - 1]) + elif k == "d": + ftime.write("%02d" % ts[_TS_MDAY]) + elif k == "H": + ftime.write("%02d" % ts[_TS_HOUR]) + elif k == "I": + ftime.write("%02d" % (ts[_TS_HOUR] % 12)) + elif k == "j": + ftime.write("%03d" % ts[_TS_YDAY]) + elif k == "m": + ftime.write("%02d" % ts[_TS_MON]) + elif k == "M": + ftime.write("%02d" % ts[_TS_MIN]) + elif k == "P": + ftime.write("AM" if ts[_TS_HOUR] < 12 else "PM") + elif k == "S": + ftime.write("%02d" % ts[_TS_SEC]) + elif k == "w": + ftime.write(str(ts[_TS_WDAY])) + elif k == "y": + ftime.write("%02d" % (ts[_TS_YEAR] % 100)) + elif k == "Y": + ftime.write(str(ts[_TS_YEAR])) + else: + ftime.write(k) + fmtsp = False + elif k == "%": + fmtsp = True + else: + ftime.write(k) + val = ftime.getvalue() + ftime.close() + return val diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/time.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/time.pyi new file mode 100644 index 000000000..26b0e4b08 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/time.pyi @@ -0,0 +1,59 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. +""" + +from __future__ import annotations +from utime import * +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TS_YEAR: int +_TS_MON: int +_TS_MDAY: int +_TS_HOUR: int +_TS_MIN: int +_TS_SEC: int +_TS_WDAY: int +_TS_YDAY: int +_TS_ISDST: int +_WDAY: Incomplete +_MDAY: Incomplete +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def strftime(datefmt, ts): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/urequests.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/urequests.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/ARDUINO_PORTENTA_C33/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/modules.json b/stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/modules.json new file mode 100644 index 000000000..283e91a75 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/modules.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "renesas-ra", + "platform": "renesas-ra", + "machine": "EK_RA4M1", + "firmware": "micropython-renesas-ra-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "sdcard.py", + "module": "sdcard" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/sdcard.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/sdcard.py new file mode 100644 index 000000000..1a271b537 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/sdcard.py @@ -0,0 +1,306 @@ +""" +MicroPython driver for SD cards using SPI bus. + +Requires an SPI bus and a CS pin. Provides readblocks and writeblocks +methods so the device can be mounted as a filesystem. + +Example usage on pyboard: + + import pyb, sdcard, os + sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) + pyb.mount(sd, '/sd2') + os.listdir('/') + +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) + os.mount(sd, '/sd') + os.listdir('/') + +""" + +from micropython import const +import time + + +_CMD_TIMEOUT = 100 + +_R1_IDLE_STATE = 1 << 0 +# R1_ERASE_RESET = 1 << 1 +_R1_ILLEGAL_COMMAND = 1 << 2 +# R1_COM_CRC_ERROR = 1 << 3 +# R1_ERASE_SEQUENCE_ERROR = 1 << 4 +# R1_ADDRESS_ERROR = 1 << 5 +# R1_PARAMETER_ERROR = 1 << 6 +_TOKEN_CMD25 = 0xFC +_TOKEN_STOP_TRAN = 0xFD +_TOKEN_DATA = 0xFE + + +class SDCard: + def __init__(self, spi, cs, baudrate=1320000): + self.spi = spi + self.cs = cs + + self.cmdbuf = bytearray(6) + self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) + for i in range(512): + self.dummybuf[i] = 0xFF + self.dummybuf_memoryview = memoryview(self.dummybuf) + + # initialise the card + self.init_card(baudrate) + + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + + def init_card(self, baudrate): + # init CS pin + self.cs.init(self.cs.OUT, value=1) + + # init SPI bus; use low data rate for initialisation + self.init_spi(100000) + + # clock card at least 100 cycles with cs high + for i in range(16): + self.spi.write(b"\xff") + + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) + for _ in range(5): + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: + break + else: + raise OSError("no SD card") + + # CMD8: determine card version + r = self.cmd(8, 0x01AA, 0x87, 4) + if r == _R1_IDLE_STATE: + self.init_card_v2() + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): + self.init_card_v1() + else: + raise OSError("couldn't determine SD card version") + + # get the number of sectors + # CMD9: response R2 (R1 byte + 16-byte block read) + if self.cmd(9, 0, 0, 0, False) != 0: + raise OSError("no response from SD card") + csd = bytearray(16) + self.readinto(csd) + if csd[0] & 0xC0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 + elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 + c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 + read_bl_len = csd[5] & 0b1111 + capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) + self.sectors = capacity // 512 + else: + raise OSError("SD card CSD format not supported") + # print('sectors', self.sectors) + + # CMD16: set block length to 512 bytes + if self.cmd(16, 512, 0) != 0: + raise OSError("can't set 512 block size") + + # set to high data rate now that it's initialised + self.init_spi(baudrate) + + def init_card_v1(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(55, 0, 0) + if self.cmd(41, 0, 0) == 0: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + # print("[SDCard] v1 card") + return + raise OSError("timeout waiting for v1 card") + + def init_card_v2(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(58, 0, 0, 4) + self.cmd(55, 0, 0) + if self.cmd(41, 0x40000000, 0) == 0: + self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte + ocr = self.tokenbuf[0] # get first byte of response, which is OCR + if not ocr & 0x40: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + else: + # SDHC/SDXC card, uses block addressing in read/write/erase commands + self.cdv = 1 + # print("[SDCard] v2 card") + return + raise OSError("timeout waiting for v2 card") + + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): + self.cs(0) + + # create and send the command + buf = self.cmdbuf + buf[0] = 0x40 | cmd + buf[1] = arg >> 24 + buf[2] = arg >> 16 + buf[3] = arg >> 8 + buf[4] = arg + buf[5] = crc + self.spi.write(buf) + + if skip1: + self.spi.readinto(self.tokenbuf, 0xFF) + + # wait for the response (response[7] == 0) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + response = self.tokenbuf[0] + if not (response & 0x80): + # this could be a big-endian integer that we are getting here + # if final<0 then store the first byte to tokenbuf and discard the rest + if final < 0: + self.spi.readinto(self.tokenbuf, 0xFF) + final = -1 - final + for j in range(final): + self.spi.write(b"\xff") + if release: + self.cs(1) + self.spi.write(b"\xff") + return response + + # timeout + self.cs(1) + self.spi.write(b"\xff") + return -1 + + def readinto(self, buf): + self.cs(0) + + # read until start byte (0xff) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + if self.tokenbuf[0] == _TOKEN_DATA: + break + time.sleep_ms(1) + else: + self.cs(1) + raise OSError("timeout waiting for response") + + # read data + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[: len(buf)] + self.spi.write_readinto(mv, buf) + + # read checksum + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + self.cs(1) + self.spi.write(b"\xff") + + def write(self, token, buf): + self.cs(0) + + # send: start of block, data, checksum + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + # check the response + if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: + self.cs(1) + self.spi.write(b"\xff") + return + + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def write_token(self, token): + self.cs(0) + self.spi.read(1, token) + self.spi.write(b"\xff") + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0x00: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def readblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, "Buffer length is invalid" + if nblocks == 1: + # CMD17: set read address for single block + if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + # receive the data and release card + self.readinto(buf) + else: + # CMD18: set read address for multiple blocks + if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + offset = 0 + mv = memoryview(buf) + while nblocks: + # receive the data and release card + self.readinto(mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + if self.cmd(12, 0, 0xFF, skip1=True): + raise OSError(5) # EIO + + def writeblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks, err = divmod(len(buf), 512) + assert nblocks and not err, "Buffer length is invalid" + if nblocks == 1: + # CMD24: set write address for single block + if self.cmd(24, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + + # send the data + self.write(_TOKEN_DATA, buf) + else: + # CMD25: set write address for first block + if self.cmd(25, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + # send the data + offset = 0 + mv = memoryview(buf) + while nblocks: + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return self.sectors + if op == 5: # get block size in bytes + return 512 diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/sdcard.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/sdcard.pyi new file mode 100644 index 000000000..3009717c8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/EK_RA4M1/sdcard.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CMD_TIMEOUT: int +_R1_IDLE_STATE: Incomplete +_R1_ILLEGAL_COMMAND: Incomplete +_TOKEN_CMD25: int +_TOKEN_STOP_TRAN: int +_TOKEN_DATA: int + +class SDCard: + spi: Incomplete + cs: Incomplete + cmdbuf: Incomplete + dummybuf: Incomplete + tokenbuf: Incomplete + dummybuf_memoryview: Incomplete + def __init__(self, spi, cs, baudrate: int = 1320000) -> None: ... + def init_spi(self, baudrate) -> None: ... + sectors: Incomplete + def init_card(self, baudrate) -> None: ... + cdv: int + def init_card_v1(self) -> None: ... + def init_card_v2(self) -> None: ... + def cmd(self, cmd, arg, crc, final: int = 0, release: bool = True, skip1: bool = False): ... + def readinto(self, buf) -> None: ... + def write(self, token, buf) -> None: ... + def write_token(self, token) -> None: ... + def readblocks(self, block_num, buf) -> None: ... + def writeblocks(self, block_num, buf) -> None: ... + def ioctl(self, op, arg): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/dht.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/dht.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/modules.json new file mode 100644 index 000000000..9c8f39fdb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/modules.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "renesas-ra", + "platform": "renesas-ra", + "machine": "GENERIC", + "firmware": "micropython-renesas-ra-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/onewire.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/modules.json b/stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/modules.json new file mode 100644 index 000000000..7c608333e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/modules.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "renesas-ra", + "platform": "renesas-ra", + "machine": "RA4M1_CLICKER", + "firmware": "micropython-renesas-ra-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "sdcard.py", + "module": "sdcard" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/sdcard.py b/stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/sdcard.py new file mode 100644 index 000000000..1a271b537 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/sdcard.py @@ -0,0 +1,306 @@ +""" +MicroPython driver for SD cards using SPI bus. + +Requires an SPI bus and a CS pin. Provides readblocks and writeblocks +methods so the device can be mounted as a filesystem. + +Example usage on pyboard: + + import pyb, sdcard, os + sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) + pyb.mount(sd, '/sd2') + os.listdir('/') + +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) + os.mount(sd, '/sd') + os.listdir('/') + +""" + +from micropython import const +import time + + +_CMD_TIMEOUT = 100 + +_R1_IDLE_STATE = 1 << 0 +# R1_ERASE_RESET = 1 << 1 +_R1_ILLEGAL_COMMAND = 1 << 2 +# R1_COM_CRC_ERROR = 1 << 3 +# R1_ERASE_SEQUENCE_ERROR = 1 << 4 +# R1_ADDRESS_ERROR = 1 << 5 +# R1_PARAMETER_ERROR = 1 << 6 +_TOKEN_CMD25 = 0xFC +_TOKEN_STOP_TRAN = 0xFD +_TOKEN_DATA = 0xFE + + +class SDCard: + def __init__(self, spi, cs, baudrate=1320000): + self.spi = spi + self.cs = cs + + self.cmdbuf = bytearray(6) + self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) + for i in range(512): + self.dummybuf[i] = 0xFF + self.dummybuf_memoryview = memoryview(self.dummybuf) + + # initialise the card + self.init_card(baudrate) + + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + + def init_card(self, baudrate): + # init CS pin + self.cs.init(self.cs.OUT, value=1) + + # init SPI bus; use low data rate for initialisation + self.init_spi(100000) + + # clock card at least 100 cycles with cs high + for i in range(16): + self.spi.write(b"\xff") + + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) + for _ in range(5): + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: + break + else: + raise OSError("no SD card") + + # CMD8: determine card version + r = self.cmd(8, 0x01AA, 0x87, 4) + if r == _R1_IDLE_STATE: + self.init_card_v2() + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): + self.init_card_v1() + else: + raise OSError("couldn't determine SD card version") + + # get the number of sectors + # CMD9: response R2 (R1 byte + 16-byte block read) + if self.cmd(9, 0, 0, 0, False) != 0: + raise OSError("no response from SD card") + csd = bytearray(16) + self.readinto(csd) + if csd[0] & 0xC0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 + elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 + c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 + read_bl_len = csd[5] & 0b1111 + capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) + self.sectors = capacity // 512 + else: + raise OSError("SD card CSD format not supported") + # print('sectors', self.sectors) + + # CMD16: set block length to 512 bytes + if self.cmd(16, 512, 0) != 0: + raise OSError("can't set 512 block size") + + # set to high data rate now that it's initialised + self.init_spi(baudrate) + + def init_card_v1(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(55, 0, 0) + if self.cmd(41, 0, 0) == 0: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + # print("[SDCard] v1 card") + return + raise OSError("timeout waiting for v1 card") + + def init_card_v2(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(58, 0, 0, 4) + self.cmd(55, 0, 0) + if self.cmd(41, 0x40000000, 0) == 0: + self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte + ocr = self.tokenbuf[0] # get first byte of response, which is OCR + if not ocr & 0x40: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + else: + # SDHC/SDXC card, uses block addressing in read/write/erase commands + self.cdv = 1 + # print("[SDCard] v2 card") + return + raise OSError("timeout waiting for v2 card") + + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): + self.cs(0) + + # create and send the command + buf = self.cmdbuf + buf[0] = 0x40 | cmd + buf[1] = arg >> 24 + buf[2] = arg >> 16 + buf[3] = arg >> 8 + buf[4] = arg + buf[5] = crc + self.spi.write(buf) + + if skip1: + self.spi.readinto(self.tokenbuf, 0xFF) + + # wait for the response (response[7] == 0) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + response = self.tokenbuf[0] + if not (response & 0x80): + # this could be a big-endian integer that we are getting here + # if final<0 then store the first byte to tokenbuf and discard the rest + if final < 0: + self.spi.readinto(self.tokenbuf, 0xFF) + final = -1 - final + for j in range(final): + self.spi.write(b"\xff") + if release: + self.cs(1) + self.spi.write(b"\xff") + return response + + # timeout + self.cs(1) + self.spi.write(b"\xff") + return -1 + + def readinto(self, buf): + self.cs(0) + + # read until start byte (0xff) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + if self.tokenbuf[0] == _TOKEN_DATA: + break + time.sleep_ms(1) + else: + self.cs(1) + raise OSError("timeout waiting for response") + + # read data + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[: len(buf)] + self.spi.write_readinto(mv, buf) + + # read checksum + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + self.cs(1) + self.spi.write(b"\xff") + + def write(self, token, buf): + self.cs(0) + + # send: start of block, data, checksum + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + # check the response + if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: + self.cs(1) + self.spi.write(b"\xff") + return + + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def write_token(self, token): + self.cs(0) + self.spi.read(1, token) + self.spi.write(b"\xff") + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0x00: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def readblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, "Buffer length is invalid" + if nblocks == 1: + # CMD17: set read address for single block + if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + # receive the data and release card + self.readinto(buf) + else: + # CMD18: set read address for multiple blocks + if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + offset = 0 + mv = memoryview(buf) + while nblocks: + # receive the data and release card + self.readinto(mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + if self.cmd(12, 0, 0xFF, skip1=True): + raise OSError(5) # EIO + + def writeblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks, err = divmod(len(buf), 512) + assert nblocks and not err, "Buffer length is invalid" + if nblocks == 1: + # CMD24: set write address for single block + if self.cmd(24, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + + # send the data + self.write(_TOKEN_DATA, buf) + else: + # CMD25: set write address for first block + if self.cmd(25, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + # send the data + offset = 0 + mv = memoryview(buf) + while nblocks: + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return self.sectors + if op == 5: # get block size in bytes + return 512 diff --git a/stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/sdcard.pyi b/stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/sdcard.pyi new file mode 100644 index 000000000..3009717c8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/renesas-ra/RA4M1_CLICKER/sdcard.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CMD_TIMEOUT: int +_R1_IDLE_STATE: Incomplete +_R1_ILLEGAL_COMMAND: Incomplete +_TOKEN_CMD25: int +_TOKEN_STOP_TRAN: int +_TOKEN_DATA: int + +class SDCard: + spi: Incomplete + cs: Incomplete + cmdbuf: Incomplete + dummybuf: Incomplete + tokenbuf: Incomplete + dummybuf_memoryview: Incomplete + def __init__(self, spi, cs, baudrate: int = 1320000) -> None: ... + def init_spi(self, baudrate) -> None: ... + sectors: Incomplete + def init_card(self, baudrate) -> None: ... + cdv: int + def init_card_v1(self) -> None: ... + def init_card_v2(self) -> None: ... + def cmd(self, cmd, arg, crc, final: int = 0, release: bool = True, skip1: bool = False): ... + def readinto(self, buf) -> None: ... + def write(self, token, buf) -> None: ... + def write_token(self, token) -> None: ... + def readblocks(self, block_num, buf) -> None: ... + def writeblocks(self, block_num, buf) -> None: ... + def ioctl(self, op, arg): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/central.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/client.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/core.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/device.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/security.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/server.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/__init__.py new file mode 100644 index 000000000..80790f0da --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/__init__.py @@ -0,0 +1,32 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from ._decoder import CBORDecoder +from ._decoder import load +from ._decoder import loads + +from ._encoder import CBOREncoder +from ._encoder import dump +from ._encoder import dumps diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/__init__.pyi new file mode 100644 index 000000000..0ef59d019 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/__init__.pyi @@ -0,0 +1,2 @@ +from ._decoder import CBORDecoder as CBORDecoder, load as load, loads as loads +from ._encoder import CBOREncoder as CBOREncoder, dump as dump, dumps as dumps diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_decoder.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_decoder.py new file mode 100644 index 000000000..8434aec26 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_decoder.py @@ -0,0 +1,254 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + + +break_marker = object() + + +class CBORSimpleValue(object): + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + def __init__(self, value): + if value < 0 or value > 255: + raise TypeError("simple value too big") + self.value = value + + def __eq__(self, other): + if isinstance(other, CBORSimpleValue): + return self.value == other.value + elif isinstance(other, int): + return self.value == other + return NotImplemented + + def __repr__(self): + return "CBORSimpleValue({self.value})".format(self=self) + + +def decode_uint(decoder, subtype, allow_indefinite=False): + # Major tag 0 + if subtype < 24: + return subtype + elif subtype == 24: + return struct.unpack(">B", decoder.read(1))[0] + elif subtype == 25: + return struct.unpack(">H", decoder.read(2))[0] + elif subtype == 26: + return struct.unpack(">L", decoder.read(4))[0] + elif subtype == 27: + return struct.unpack(">Q", decoder.read(8))[0] + elif subtype == 31 and allow_indefinite: + return None + else: + raise CBORDecodeError("unknown unsigned integer subtype 0x%x" % subtype) + + +def decode_negint(decoder, subtype): + # Major tag 1 + uint = decode_uint(decoder, subtype) + return -uint - 1 + + +def decode_bytestring(decoder, subtype): + # Major tag 2 + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + buf = bytearray() + while True: + initial_byte = decoder.read(1)[0] + if initial_byte == 255: + return buf + else: + length = decode_uint(decoder, initial_byte & 31) + value = decoder.read(length) + buf.extend(value) + else: + return decoder.read(length) + + +def decode_string(decoder, subtype): + # Major tag 3 + return decode_bytestring(decoder, subtype).decode("utf-8") + + +def decode_array(decoder, subtype): + # Major tag 4 + items = [] + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + value = decoder.decode() + if value is break_marker: + break + else: + items.append(value) + else: + for _ in range(length): + item = decoder.decode() + items.append(item) + return items + + +def decode_map(decoder, subtype): + # Major tag 5 + dictionary = {} + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + key = decoder.decode() + if key is break_marker: + break + else: + value = decoder.decode() + dictionary[key] = value + else: + for _ in range(length): + key = decoder.decode() + value = decoder.decode() + dictionary[key] = value + + return dictionary + + +def decode_special(decoder, subtype): + # Simple value + if subtype < 20: + return CBORSimpleValue(subtype) + + # Major tag 7 + return special_decoders[subtype](decoder) + + +def decode_simple_value(decoder): + return CBORSimpleValue(struct.unpack(">B", decoder.read(1))[0]) + + +def decode_float16(decoder): + decoder.read(2) + raise NotImplementedError # no float16 unpack function + + +def decode_float32(decoder): + return struct.unpack(">f", decoder.read(4))[0] + + +def decode_float64(decoder): + return struct.unpack(">d", decoder.read(8))[0] + + +major_decoders = { + 0: decode_uint, + 1: decode_negint, + 2: decode_bytestring, + 3: decode_string, + 4: decode_array, + 5: decode_map, + 7: decode_special, +} + +special_decoders = { + 20: lambda self: False, + 21: lambda self: True, + 22: lambda self: None, + # 23 is undefined + 24: decode_simple_value, + 25: decode_float16, + 26: decode_float32, + 27: decode_float64, + 31: lambda self: break_marker, +} + + +class CBORDecoder(object): + """ + Deserializes a CBOR encoded byte stream. + """ + + def __init__(self, fp): + self.fp = fp + + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + data = self.fp.read(amount) + if len(data) < amount: + raise CBORDecodeError("premature end of stream (expected to read {} bytes, got {} instead)".format(amount, len(data))) + + return data + + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + try: + initial_byte = self.fp.read(1)[0] + major_type = initial_byte >> 5 + subtype = initial_byte & 31 + except Exception as e: + raise CBORDecodeError("error reading major type at index {}: {}".format(self.fp.tell(), e)) + + decoder = major_decoders[major_type] + try: + return decoder(self, subtype) + except CBORDecodeError: + raise + except Exception as e: + raise CBORDecodeError("error decoding value {}".format(e)) # tell doesn't work on micropython at the moment + + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + fp = io.BytesIO(payload) + return CBORDecoder(fp, **kwargs).decode() + + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + return CBORDecoder(fp, **kwargs).decode() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_decoder.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_decoder.pyi new file mode 100644 index 000000000..d4daffe85 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_decoder.pyi @@ -0,0 +1,66 @@ +from _typeshed import Incomplete + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + +break_marker: Incomplete + +class CBORSimpleValue: + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + value: Incomplete + def __init__(self, value) -> None: ... + def __eq__(self, other): ... + def __repr__(self) -> str: ... + +def decode_uint(decoder, subtype, allow_indefinite: bool = False): ... +def decode_negint(decoder, subtype): ... +def decode_bytestring(decoder, subtype): ... +def decode_string(decoder, subtype): ... +def decode_array(decoder, subtype): ... +def decode_map(decoder, subtype): ... +def decode_special(decoder, subtype): ... +def decode_simple_value(decoder): ... +def decode_float16(decoder) -> None: ... +def decode_float32(decoder): ... +def decode_float64(decoder): ... + +major_decoders: Incomplete +special_decoders: Incomplete + +class CBORDecoder: + """ + Deserializes a CBOR encoded byte stream. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_encoder.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_encoder.py new file mode 100644 index 000000000..fe8715468 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_encoder.py @@ -0,0 +1,182 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + + +def encode_length(major_tag, length): + if length < 24: + return struct.pack(">B", major_tag | length) + elif length < 256: + return struct.pack(">BB", major_tag | 24, length) + elif length < 65536: + return struct.pack(">BH", major_tag | 25, length) + elif length < 4294967296: + return struct.pack(">BL", major_tag | 26, length) + else: + return struct.pack(">BQ", major_tag | 27, length) + + +def encode_semantic(encoder, tag, value): + encoder.write(encode_length(0xC0, tag)) + encoder.encode(value) + + +def encode_float(encoder, value): + # Handle special values efficiently + import math + + if math.isnan(value): + encoder.write(b"\xf9\x7e\x00") + elif math.isinf(value): + encoder.write(b"\xf9\x7c\x00" if value > 0 else b"\xf9\xfc\x00") + else: + encoder.write(struct.pack(">Bd", 0xFB, value)) + + +def encode_int(encoder, value): + # Big integers (2 ** 64 and over) + if value >= 18446744073709551616 or value < -18446744073709551616: + if value >= 0: + major_type = 0x02 + else: + major_type = 0x03 + value = -value - 1 + + values = [] + while value > 0: + value, remainder = divmod(value, 256) + values.insert(0, remainder) + + payload = bytes(values) + encode_semantic(encoder, major_type, payload) + elif value >= 0: + encoder.write(encode_length(0, value)) + else: + encoder.write(encode_length(0x20, abs(value) - 1)) + + +def encode_bytestring(encoder, value): + encoder.write(encode_length(0x40, len(value)) + value) + + +def encode_bytearray(encoder, value): + encode_bytestring(encoder, bytes(value)) + + +def encode_string(encoder, value): + encoded = value.encode("utf-8") + encoder.write(encode_length(0x60, len(encoded)) + encoded) + + +def encode_map(encoder, value): + encoder.write(encode_length(0xA0, len(value))) + for key, val in value.items(): + encoder.encode(key) + encoder.encode(val) + + +def encode_array(encoder, value): + encoder.write(encode_length(0x80, len(value))) + for item in value: + encoder.encode(item) + + +def encode_boolean(encoder, value): + encoder.write(b"\xf5" if value else b"\xf4") + + +def encode_none(encoder, value): + encoder.write(b"\xf6") + + +cbor_encoders = { # supported data types and the encoder to use. + bytes: encode_bytestring, + bytearray: encode_bytearray, + str: encode_string, + int: encode_int, + float: encode_float, + bool: encode_boolean, + type(None): encode_none, + list: encode_array, + dict: encode_map, +} + + +class CBOREncoder(object): + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + def __init__(self, fp): + self.fp = fp + + def _find_encoder(self, obj): + return cbor_encoders[type(obj)] + + def write(self, data): + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + self.fp.write(data) + + def encode(self, obj): + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + encoder = self._find_encoder(obj) + if not encoder: + raise CBOREncodeError("cannot serialize type %s" % type(obj)) + encoder(self, obj) + + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + fp = io.BytesIO() + dump(obj, fp, **kwargs) + return fp.getvalue() + + +def dump(obj, fp, **kwargs): + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ + CBOREncoder(fp, **kwargs).encode(obj) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_encoder.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_encoder.pyi new file mode 100644 index 000000000..8cd761686 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/cbor2/_encoder.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + +def encode_length(major_tag, length): ... +def encode_semantic(encoder, tag, value) -> None: ... +def encode_float(encoder, value) -> None: ... +def encode_int(encoder, value) -> None: ... +def encode_bytestring(encoder, value) -> None: ... +def encode_bytearray(encoder, value) -> None: ... +def encode_string(encoder, value) -> None: ... +def encode_map(encoder, value) -> None: ... +def encode_array(encoder, value) -> None: ... +def encode_boolean(encoder, value) -> None: ... +def encode_none(encoder, value) -> None: ... + +cbor_encoders: Incomplete + +class CBOREncoder: + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def _find_encoder(self, obj): ... + def write(self, data) -> None: + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + def encode(self, obj) -> None: + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + +def dump(obj, fp, **kwargs) -> None: + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/espflash.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/espflash.py new file mode 100644 index 000000000..e078463d7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/espflash.py @@ -0,0 +1,303 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2022 Ibrahim Abdelkader +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# A minimal esptool implementation to communicate with ESP32 ROM bootloader. +# Note this tool does Not support advanced features, other ESP chips or stub loading. +# This is only meant to be used for updating the U-blox Nina module firmware. + +import os +import struct +from micropython import const +from time import sleep +import binascii + +_CMD_SYNC = 0x08 +_CMD_CHANGE_BAUDRATE = 0x0F + +_CMD_ESP_READ_REG = 0x0A +_CMD_ESP_WRITE_REG = 0x09 + +_CMD_SPI_ATTACH = 0x0D +_CMD_SPI_FLASH_MD5 = 0x13 +_CMD_SPI_FLASH_PARAMS = 0x0B +_CMD_SPI_FLASH_BEGIN = 0x02 +_CMD_SPI_FLASH_DATA = 0x03 +_CMD_SPI_FLASH_END = 0x04 + +_FLASH_ID = 0 +_FLASH_REG_BASE = 0x60002000 +_FLASH_BLOCK_SIZE = 64 * 1024 +_FLASH_SECTOR_SIZE = 4 * 1024 +_FLASH_PAGE_SIZE = 256 + +_ESP_ERRORS = { + 0x05: "Received message is invalid", + 0x06: "Failed to act on received message", + 0x07: "Invalid CRC in message", + 0x08: "Flash write error", + 0x09: "Flash read error", + 0x0A: "Flash read length error", + 0x0B: "Deflate error", +} + + +class ESPFlash: + def __init__(self, reset, gpio0, uart, log_enabled=False): + self.uart = uart + self.reset_pin = reset + self.gpio0_pin = gpio0 + self.log = log_enabled + self.baudrate = 115200 + self.md5sum = None + try: + import hashlib + + if hasattr(hashlib, "md5"): + self.md5sum = hashlib.md5() + except ImportError: + pass + + def _log(self, data, out=True): + if self.log: + size = len(data) + print( + f"out({size}) => " if out else f"in({size}) <= ", + "".join("%.2x" % (i) for i in data[0:10]), + ) + + def _uart_drain(self): + while self.uart.read(1) is not None: + pass + + def _read_reg(self, addr): + v, d = self._command(_CMD_ESP_READ_REG, struct.pack("= 8: + (flag, _cmd, size, val) = struct.unpack(" {baudrate}") + self._uart_drain() + self._command(_CMD_CHANGE_BAUDRATE, struct.pack("> 16 + if flash_bits < 0x12 or flash_bits > 0x19: + raise Exception(f"Unexpected flash size bits: 0x{flash_bits:02X}.") + + flash_size = 2**flash_bits + print(f"Flash size {flash_size / 1024 / 1024} MBytes") + return flash_size + + def flash_attach(self): + self._command(_CMD_SPI_ATTACH, struct.pack(" {seq+erase_blocks}...") + self._command( + _CMD_SPI_FLASH_BEGIN, + struct.pack(" None: ... + def _log(self, data, out: bool = True) -> None: ... + def _uart_drain(self) -> None: ... + def _read_reg(self, addr): ... + def _write_reg(self, addr, data, mask: int = 4294967295, delay: int = 0) -> None: ... + def _poll_reg(self, addr, flag, retry: int = 10, delay: float = 0.05) -> None: ... + def _write_slip(self, pkt) -> None: ... + def _read_slip(self): ... + def _strerror(self, err): ... + def _checksum(self, data): ... + def _command(self, cmd, payload: bytes = b"", checksum: int = 0): ... + def set_baudrate(self, baudrate, timeout: int = 350) -> None: ... + def bootloader(self, retry: int = 6): ... + def flash_read_size(self): ... + def flash_attach(self) -> None: ... + def flash_config(self, flash_size=...) -> None: ... + def flash_write_file(self, path, blksize: int = 4096) -> None: ... + def flash_verify_file(self, path, digest=None, offset: int = 0) -> None: ... + def reboot(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/logging.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/logging.py new file mode 100644 index 000000000..edee407c6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/logging.py @@ -0,0 +1,253 @@ +from micropython import const +import io +import sys +import time + +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 + +_DEFAULT_LEVEL = WARNING + +_level_dict = { + CRITICAL: "CRITICAL", + ERROR: "ERROR", + WARNING: "WARNING", + INFO: "INFO", + DEBUG: "DEBUG", + NOTSET: "NOTSET", +} + +_loggers = {} +_stream = sys.stderr +_default_fmt = "%(levelname)s:%(name)s:%(message)s" +_default_datefmt = "%Y-%m-%d %H:%M:%S" + + +class LogRecord: + def set(self, name, level, message): + self.name = name + self.levelno = level + self.levelname = _level_dict[level] + self.message = message + self.ct = time.time() + self.msecs = int((self.ct - int(self.ct)) * 1000) + self.asctime = None + + +class Handler: + def __init__(self, level=NOTSET): + self.level = level + self.formatter = None + + def close(self): + pass + + def setLevel(self, level): + self.level = level + + def setFormatter(self, formatter): + self.formatter = formatter + + def format(self, record): + return self.formatter.format(record) + + +class StreamHandler(Handler): + def __init__(self, stream=None): + super().__init__() + self.stream = _stream if stream is None else stream + self.terminator = "\n" + + def close(self): + if hasattr(self.stream, "flush"): + self.stream.flush() + + def emit(self, record): + if record.levelno >= self.level: + self.stream.write(self.format(record) + self.terminator) + + +class FileHandler(StreamHandler): + def __init__(self, filename, mode="a", encoding="UTF-8"): + super().__init__(stream=open(filename, mode=mode, encoding=encoding)) + + def close(self): + super().close() + self.stream.close() + + +class Formatter: + def __init__(self, fmt=None, datefmt=None): + self.fmt = _default_fmt if fmt is None else fmt + self.datefmt = _default_datefmt if datefmt is None else datefmt + + def usesTime(self): + return "asctime" in self.fmt + + def formatTime(self, datefmt, record): + if hasattr(time, "strftime"): + return time.strftime(datefmt, time.localtime(record.ct)) + return None + + def format(self, record): + if self.usesTime(): + record.asctime = self.formatTime(self.datefmt, record) + return self.fmt % { + "name": record.name, + "message": record.message, + "msecs": record.msecs, + "asctime": record.asctime, + "levelname": record.levelname, + } + + +class Logger: + def __init__(self, name, level=NOTSET): + self.name = name + self.level = level + self.handlers = [] + self.record = LogRecord() + + def setLevel(self, level): + self.level = level + + def isEnabledFor(self, level): + return level >= self.getEffectiveLevel() + + def getEffectiveLevel(self): + return self.level or getLogger().level or _DEFAULT_LEVEL + + def log(self, level, msg, *args): + if self.isEnabledFor(level): + if args: + if isinstance(args[0], dict): + args = args[0] + msg = msg % args + self.record.set(self.name, level, msg) + handlers = self.handlers + if not handlers: + handlers = getLogger().handlers + for h in handlers: + h.emit(self.record) + + def debug(self, msg, *args): + self.log(DEBUG, msg, *args) + + def info(self, msg, *args): + self.log(INFO, msg, *args) + + def warning(self, msg, *args): + self.log(WARNING, msg, *args) + + def error(self, msg, *args): + self.log(ERROR, msg, *args) + + def critical(self, msg, *args): + self.log(CRITICAL, msg, *args) + + def exception(self, msg, *args, exc_info=True): + self.log(ERROR, msg, *args) + tb = None + if isinstance(exc_info, BaseException): + tb = exc_info + elif hasattr(sys, "exc_info"): + tb = sys.exc_info()[1] + if tb: + buf = io.StringIO() + sys.print_exception(tb, buf) + self.log(ERROR, buf.getvalue()) + + def addHandler(self, handler): + self.handlers.append(handler) + + def hasHandlers(self): + return len(self.handlers) > 0 + + +def getLogger(name=None): + if name is None: + name = "root" + if name not in _loggers: + _loggers[name] = Logger(name) + if name == "root": + basicConfig() + return _loggers[name] + + +def log(level, msg, *args): + getLogger().log(level, msg, *args) + + +def debug(msg, *args): + getLogger().debug(msg, *args) + + +def info(msg, *args): + getLogger().info(msg, *args) + + +def warning(msg, *args): + getLogger().warning(msg, *args) + + +def error(msg, *args): + getLogger().error(msg, *args) + + +def critical(msg, *args): + getLogger().critical(msg, *args) + + +def exception(msg, *args, exc_info=True): + getLogger().exception(msg, *args, exc_info=exc_info) + + +def shutdown(): + for k, logger in _loggers.items(): + for h in logger.handlers: + h.close() + _loggers.pop(logger, None) + + +def addLevelName(level, name): + _level_dict[level] = name + + +def basicConfig( + filename=None, + filemode="a", + format=None, + datefmt=None, + level=WARNING, + stream=None, + encoding="UTF-8", + force=False, +): + if "root" not in _loggers: + _loggers["root"] = Logger("root") + + logger = _loggers["root"] + + if force or not logger.handlers: + for h in logger.handlers: + h.close() + logger.handlers = [] + + if filename is None: + handler = StreamHandler(stream) + else: + handler = FileHandler(filename, filemode, encoding) + + handler.setLevel(level) + handler.setFormatter(Formatter(format, datefmt)) + + logger.setLevel(level) + logger.addHandler(handler) + + +if hasattr(sys, "atexit"): + sys.atexit(shutdown) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/logging.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/logging.pyi new file mode 100644 index 000000000..856bcccf7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/logging.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete +from micropython import const as const + +CRITICAL: int +ERROR: int +WARNING: int +INFO: int +DEBUG: int +NOTSET: int +_DEFAULT_LEVEL = WARNING +_level_dict: Incomplete +_loggers: Incomplete +_stream: Incomplete +_default_fmt: str +_default_datefmt: str + +class LogRecord: + name: Incomplete + levelno: Incomplete + levelname: Incomplete + message: Incomplete + ct: Incomplete + msecs: Incomplete + asctime: Incomplete + def set(self, name, level, message) -> None: ... + +class Handler: + level: Incomplete + formatter: Incomplete + def __init__(self, level=...) -> None: ... + def close(self) -> None: ... + def setLevel(self, level) -> None: ... + def setFormatter(self, formatter) -> None: ... + def format(self, record): ... + +class StreamHandler(Handler): + stream: Incomplete + terminator: str + def __init__(self, stream=None) -> None: ... + def close(self) -> None: ... + def emit(self, record) -> None: ... + +class FileHandler(StreamHandler): + def __init__(self, filename, mode: str = "a", encoding: str = "UTF-8") -> None: ... + def close(self) -> None: ... + +class Formatter: + fmt: Incomplete + datefmt: Incomplete + def __init__(self, fmt=None, datefmt=None) -> None: ... + def usesTime(self): ... + def formatTime(self, datefmt, record): ... + def format(self, record): ... + +class Logger: + name: Incomplete + level: Incomplete + handlers: Incomplete + record: Incomplete + def __init__(self, name, level=...) -> None: ... + def setLevel(self, level) -> None: ... + def isEnabledFor(self, level): ... + def getEffectiveLevel(self): ... + def log(self, level, msg, *args) -> None: ... + def debug(self, msg, *args) -> None: ... + def info(self, msg, *args) -> None: ... + def warning(self, msg, *args) -> None: ... + def error(self, msg, *args) -> None: ... + def critical(self, msg, *args) -> None: ... + def exception(self, msg, *args, exc_info: bool = True) -> None: ... + def addHandler(self, handler) -> None: ... + def hasHandlers(self): ... + +def getLogger(name=None): ... +def log(level, msg, *args) -> None: ... +def debug(msg, *args) -> None: ... +def info(msg, *args) -> None: ... +def warning(msg, *args) -> None: ... +def error(msg, *args) -> None: ... +def critical(msg, *args) -> None: ... +def exception(msg, *args, exc_info: bool = True) -> None: ... +def shutdown() -> None: ... +def addLevelName(level, name) -> None: ... +def basicConfig( + filename=None, filemode: str = "a", format=None, datefmt=None, level=..., stream=None, encoding: str = "UTF-8", force: bool = False +) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.py new file mode 100644 index 000000000..1fd703d1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.py @@ -0,0 +1,272 @@ +""" +LSM6DSOX STMicro driver for MicroPython based on LSM9DS1: +Source repo: https://github.com/hoihu/projects/tree/master/raspi-hat + +The MIT License (MIT) + +Copyright (c) 2021 Damien P. George +Copyright (c) 2021-2023 Ibrahim Abdelkader + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Basic example usage: + +import time +from lsm6dsox import LSM6DSOX + +from machine import Pin, SPI, I2C +# Init in I2C mode. +lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12))) + +# Or init in SPI mode. +#lsm = LSM6DSOX(SPI(5), cs=Pin(10)) + +while (True): + print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.accel())) + print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.gyro())) + print("") + time.sleep_ms(100) +""" + +import array +from micropython import const +import time + +_CTRL3_C = 0x12 +_CTRL1_XL = 0x10 +_CTRL8_XL = 0x17 +_CTRL9_XL = 0x18 + +_CTRL2_G = 0x11 +_CTRL7_G = 0x16 + +_OUTX_L_G = 0x22 +_OUTX_L_XL = 0x28 +_MLC_STATUS = 0x38 + +_DEFAULT_ADDR = 0x6A +_WHO_AM_I_REG = 0x0F + +_FUNC_CFG_ACCESS = 0x01 +_FUNC_CFG_BANK_USER = 0 +_FUNC_CFG_BANK_HUB = 1 +_FUNC_CFG_BANK_EMBED = 2 + +_MLC0_SRC = 0x70 +_MLC_INT1 = 0x0D +_TAP_CFG0 = 0x56 + +_EMB_FUNC_EN_A = 0x04 +_EMB_FUNC_EN_B = 0x05 + + +class LSM6DSOX: + def __init__( + self, + bus, + cs=None, + address=_DEFAULT_ADDR, + gyro_odr=104, + accel_odr=104, + gyro_scale=2000, + accel_scale=4, + ucf=None, + ): + """Initalizes Gyro and Accelerator. + accel_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz) + gyro_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz) + gyro_scale: (245dps, 500dps, 1000dps, 2000dps) + accel_scale: (+/-2g, +/-4g, +/-8g, +-16g) + ucf: MLC program to load. + """ + self.bus = bus + self.cs = cs + self.address = address + self._use_i2c = hasattr(self.bus, "readfrom_mem") + + if not self._use_i2c and cs is None: + raise ValueError("A CS pin must be provided in SPI mode") + + # check the id of the Accelerometer/Gyro + if self._read_reg(_WHO_AM_I_REG) != 108: + raise OSError("No LSM6DS device was found at address 0x%x" % (self.address)) + + # allocate scratch buffer for efficient conversions and memread op's + self.scratch_int = array.array("h", [0, 0, 0]) + + SCALE_GYRO = {250: 0, 500: 1, 1000: 2, 2000: 3} + SCALE_ACCEL = {2: 0, 4: 2, 8: 3, 16: 1} + # XL_HM_MODE = 0 by default. G_HM_MODE = 0 by default. + ODR = { + 0: 0x00, + 1.6: 0x08, + 3.33: 0x09, + 6.66: 0x0A, + 12.5: 0x01, + 26: 0x02, + 52: 0x03, + 104: 0x04, + 208: 0x05, + 416: 0x06, + 888: 0x07, + } + + gyro_odr = round(gyro_odr, 2) + accel_odr = round(accel_odr, 2) + + # Sanity checks + if gyro_odr not in ODR: + raise ValueError("Invalid sampling rate: %d" % gyro_odr) + if gyro_scale not in SCALE_GYRO: + raise ValueError("invalid gyro scaling: %d" % gyro_scale) + if accel_odr not in ODR: + raise ValueError("Invalid sampling rate: %d" % accel_odr) + if accel_scale not in SCALE_ACCEL: + raise ValueError("invalid accelerometer scaling: %d" % accel_scale) + + # Soft-reset the device. + self.reset() + + # Load and configure MLC if UCF file is provided + if ucf is not None: + self.load_mlc(ucf) + + # Set Gyroscope datarate and scale. + # Note output from LPF2 second filtering stage is selected. See Figure 18. + self._write_reg(_CTRL1_XL, (ODR[accel_odr] << 4) | (SCALE_ACCEL[accel_scale] << 2) | 2) + + # Enable LPF2 and HPF fast-settling mode, ODR/4 + self._write_reg(_CTRL8_XL, 0x09) + + # Set Gyroscope datarate and scale. + self._write_reg(_CTRL2_G, (ODR[gyro_odr] << 4) | (SCALE_GYRO[gyro_scale] << 2) | 0) + + self.gyro_scale = 32768 / gyro_scale + self.accel_scale = 32768 / accel_scale + + def _read_reg(self, reg, size=1): + if self._use_i2c: + buf = self.bus.readfrom_mem(self.address, reg, size) + else: + try: + self.cs(0) + self.bus.write(bytes([reg | 0x80])) + buf = self.bus.read(size) + finally: + self.cs(1) + if size == 1: + return int(buf[0]) + return [int(x) for x in buf] + + def _write_reg(self, reg, val): + if self._use_i2c: + self.bus.writeto_mem(self.address, reg, bytes([val])) + else: + try: + self.cs(0) + self.bus.write(bytes([reg, val])) + finally: + self.cs(1) + + def _read_reg_into(self, reg, buf): + if self._use_i2c: + self.bus.readfrom_mem_into(self.address, reg, buf) + else: + try: + self.cs(0) + self.bus.write(bytes([reg | 0x80])) + self.bus.readinto(buf) + finally: + self.cs(1) + + def reset(self): + self._write_reg(_CTRL3_C, self._read_reg(_CTRL3_C) | 0x1) + for i in range(10): + if (self._read_reg(_CTRL3_C) & 0x01) == 0: + return + time.sleep_ms(10) + raise OSError("Failed to reset LSM6DS device.") + + def set_mem_bank(self, bank): + cfg = self._read_reg(_FUNC_CFG_ACCESS) & 0x3F + self._write_reg(_FUNC_CFG_ACCESS, cfg | (bank << 6)) + + def set_embedded_functions(self, enable, emb_ab=None): + self.set_mem_bank(_FUNC_CFG_BANK_EMBED) + if enable: + self._write_reg(_EMB_FUNC_EN_A, emb_ab[0]) + self._write_reg(_EMB_FUNC_EN_B, emb_ab[1]) + else: + emb_a = self._read_reg(_EMB_FUNC_EN_A) + emb_b = self._read_reg(_EMB_FUNC_EN_B) + self._write_reg(_EMB_FUNC_EN_A, (emb_a & 0xC7)) + self._write_reg(_EMB_FUNC_EN_B, (emb_b & 0xE6)) + emb_ab = (emb_a, emb_b) + + self.set_mem_bank(_FUNC_CFG_BANK_USER) + return emb_ab + + def load_mlc(self, ucf): + # Load MLC config from file + with open(ucf, "r") as ucf_file: + for l in ucf_file: + if l.startswith("Ac"): + v = [int(v, 16) for v in l.strip().split(" ")[1:3]] + self._write_reg(v[0], v[1]) + + emb_ab = self.set_embedded_functions(False) + + # Disable I3C interface + self._write_reg(_CTRL9_XL, self._read_reg(_CTRL9_XL) | 0x01) + + # Enable Block Data Update + self._write_reg(_CTRL3_C, self._read_reg(_CTRL3_C) | 0x40) + + # Route signals on interrupt pin 1 + self.set_mem_bank(_FUNC_CFG_BANK_EMBED) + self._write_reg(_MLC_INT1, self._read_reg(_MLC_INT1) & 0x01) + self.set_mem_bank(_FUNC_CFG_BANK_USER) + + # Configure interrupt pin mode + self._write_reg(_TAP_CFG0, self._read_reg(_TAP_CFG0) | 0x41) + + self.set_embedded_functions(True, emb_ab) + + def mlc_output(self): + buf = None + if self._read_reg(_MLC_STATUS) & 0x1: + self._read_reg(0x1A, size=12) + self.set_mem_bank(_FUNC_CFG_BANK_EMBED) + buf = self._read_reg(_MLC0_SRC, 8) + self.set_mem_bank(_FUNC_CFG_BANK_USER) + return buf + + def gyro(self): + """Returns gyroscope vector in degrees/sec.""" + mv = memoryview(self.scratch_int) + f = self.gyro_scale + self._read_reg_into(_OUTX_L_G, mv) + return (mv[0] / f, mv[1] / f, mv[2] / f) + + def accel(self): + """Returns acceleration vector in gravity units (9.81m/s^2).""" + mv = memoryview(self.scratch_int) + f = self.accel_scale + self._read_reg_into(_OUTX_L_XL, mv) + return (mv[0] / f, mv[1] / f, mv[2] / f) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.pyi new file mode 100644 index 000000000..07a181c4b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/lsm6dsox.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CTRL3_C: int +_CTRL1_XL: int +_CTRL8_XL: int +_CTRL9_XL: int +_CTRL2_G: int +_CTRL7_G: int +_OUTX_L_G: int +_OUTX_L_XL: int +_MLC_STATUS: int +_DEFAULT_ADDR: int +_WHO_AM_I_REG: int +_FUNC_CFG_ACCESS: int +_FUNC_CFG_BANK_USER: int +_FUNC_CFG_BANK_HUB: int +_FUNC_CFG_BANK_EMBED: int +_MLC0_SRC: int +_MLC_INT1: int +_TAP_CFG0: int +_EMB_FUNC_EN_A: int +_EMB_FUNC_EN_B: int + +class LSM6DSOX: + bus: Incomplete + cs: Incomplete + address: Incomplete + _use_i2c: Incomplete + scratch_int: Incomplete + gyro_scale: Incomplete + accel_scale: Incomplete + def __init__( + self, bus, cs=None, address=..., gyro_odr: int = 104, accel_odr: int = 104, gyro_scale: int = 2000, accel_scale: int = 4, ucf=None + ) -> None: + """Initalizes Gyro and Accelerator. + accel_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz) + gyro_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz) + gyro_scale: (245dps, 500dps, 1000dps, 2000dps) + accel_scale: (+/-2g, +/-4g, +/-8g, +-16g) + ucf: MLC program to load. + """ + def _read_reg(self, reg, size: int = 1): ... + def _write_reg(self, reg, val) -> None: ... + def _read_reg_into(self, reg, buf) -> None: ... + def reset(self) -> None: ... + def set_mem_bank(self, bank) -> None: ... + def set_embedded_functions(self, enable, emb_ab=None): ... + def load_mlc(self, ucf) -> None: ... + def mlc_output(self): ... + def gyro(self): + """Returns gyroscope vector in degrees/sec.""" + def accel(self): + """Returns acceleration vector in gravity units (9.81m/s^2).""" diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/modules.json new file mode 100644 index 000000000..41429b226 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/modules.json @@ -0,0 +1,156 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "ARDUINO_NANO_RP2040_CONNECT", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "cbor2/__init__.py", + "module": "__init__" + }, + { + "file": "cbor2/_decoder.py", + "module": "_decoder" + }, + { + "file": "cbor2/_encoder.py", + "module": "_encoder" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "espflash.py", + "module": "espflash" + }, + { + "file": "logging.py", + "module": "logging" + }, + { + "file": "lsm6dsox.py", + "module": "lsm6dsox" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "senml/__init__.py", + "module": "__init__" + }, + { + "file": "senml/senml_base.py", + "module": "senml_base" + }, + { + "file": "senml/senml_pack.py", + "module": "senml_pack" + }, + { + "file": "senml/senml_record.py", + "module": "senml_record" + }, + { + "file": "senml/senml_unit.py", + "module": "senml_unit" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "time.py", + "module": "time" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/__init__.py new file mode 100644 index 000000000..908375fdb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/__init__.py @@ -0,0 +1,29 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from .senml_base import SenmlBase +from .senml_pack import SenmlPack +from .senml_record import SenmlRecord +from .senml_unit import SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/__init__.pyi new file mode 100644 index 000000000..c72285dc4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/__init__.pyi @@ -0,0 +1,4 @@ +from .senml_base import SenmlBase as SenmlBase +from .senml_pack import SenmlPack as SenmlPack +from .senml_record import SenmlRecord as SenmlRecord +from .senml_unit import SenmlUnits as SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_base.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_base.py new file mode 100644 index 000000000..b277c9477 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_base.py @@ -0,0 +1,30 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +class SenmlBase(object): + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_base.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_base.pyi new file mode 100644 index 000000000..240f185ce --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_base.pyi @@ -0,0 +1,4 @@ +class SenmlBase: + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_pack.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_pack.py new file mode 100644 index 000000000..5a0554467 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_pack.py @@ -0,0 +1,358 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from senml.senml_record import SenmlRecord +from senml.senml_base import SenmlBase +import json +import cbor2 + + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + def __init__(self, list): + self._list = list + self._index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self._index < len(self._list): + res = self._list[self._index] + self._index += 1 + return res + else: + raise StopIteration + + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings = { + "bn": "bn", + "bt": "bt", + "bu": "bu", + "bv": "bv", + "bs": "bs", + "n": "n", + "u": "u", + "v": "v", + "vs": "vs", + "vb": "vb", + "vd": "vd", + "s": "s", + "t": "t", + "ut": "ut", + } + + def __init__(self, name, callback=None): + """ + initialize the object + :param name: {string} the name of the pack + """ + self._data = [] + self.name = name + self._base_value = None + self._base_time = None + self._base_sum = None + self.base_unit = None + self._parent = None # a pack can also be the child of another pack. + self.actuate = callback # actuate callback function + + def __iter__(self): + return SenmlPackIterator(self._data) + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + return self._base_value + + @base_value.setter + def base_value(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_value") + self._base_value = value + + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + return self._base_sum + + @base_sum.setter + def base_sum(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_sum") + self._base_sum = value + + @property + def base_time(self): + return self._base_time + + @base_time.setter + def base_time(self, value): + self._check_value_type(value, "base_time") + self._base_time = value + + def _check_value_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + def from_json(self, data): + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + records = json.loads(data) # load the raw senml data + self._process_incomming_data(records, SenmlPack.json_mappings) + + def _process_incomming_data(self, records, naming_map): + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + cur_pack_el = self + new_pack = False + for item in records: + if naming_map["bn"] in item: # ref to a pack element, either this or a child pack. + if item[naming_map["bn"]] != self.name: + pack_el = [x for x in self._data if x.name == item[naming_map["bn"]]] + else: + pack_el = [self] + if len(pack_el) > 0: + cur_pack_el = pack_el[0] + new_pack = False + else: + device = SenmlPack(item[naming_map["bn"]]) + self._data.append(device) + cur_pack_el = device + new_pack = True + + if ( + naming_map["bv"] in item + ): # need to copy the base value assigned to the pack element so we can do proper conversion for actuators. + cur_pack_el.base_value = item[naming_map["bv"]] + + rec_el = [x for x in cur_pack_el._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + else: + rec_el = [x for x in self._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + + def do_actuate(self, raw, naming_map, device=None): + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + rec = SenmlRecord(raw[naming_map["n"]]) + if device: + device.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=device) + else: + self.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=None) + + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + converted = [] + self._build_rec_dict(SenmlPack.json_mappings, converted) + return json.dumps(converted) + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + internalList = [] + for item in self._data: + item._build_rec_dict(naming_map, internalList) + if len(internalList) > 0: + first_rec = internalList[0] + else: + first_rec = {} + internalList.append(first_rec) + + if self.name: + first_rec[naming_map["bn"]] = self.name + if self.base_value: + first_rec[naming_map["bv"]] = self.base_value + if self.base_unit: + first_rec[naming_map["bu"]] = self.base_unit + if self.base_sum: + first_rec[naming_map["bs"]] = self.base_sum + if self.base_time: + first_rec[naming_map["bt"]] = self.base_time + appendTo.extend(internalList) + + def from_cbor(self, data): + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + records = cbor2.loads(data) # load the raw senml data + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + self._process_incomming_data(records, naming_map) + + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + converted = [] + self._build_rec_dict(naming_map, converted) + return cbor2.dumps(converted) + + def add(self, item): + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if item._parent is not None: + raise Exception("item is already part of a pack") + + self._data.append(item) + item._parent = self + + def remove(self, item): + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if not item._parent == self: + raise Exception("item is not part of this pack") + + self._data.remove(item) + item._parent = None + + def clear(self): + """ + clear the list of the pack + :return: None + """ + for item in self._data: + item._parent = None + self._data = [] diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_pack.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_pack.pyi new file mode 100644 index 000000000..57a0cf547 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_pack.pyi @@ -0,0 +1,143 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase +from senml.senml_record import SenmlRecord as SenmlRecord + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + _list: Incomplete + _index: int + def __init__(self, list) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings: Incomplete + _data: Incomplete + name: Incomplete + _base_value: Incomplete + _base_time: Incomplete + _base_sum: Incomplete + base_unit: Incomplete + _parent: Incomplete + actuate: Incomplete + def __init__(self, name, callback=None) -> None: + """ + initialize the object + :param name: {string} the name of the pack + """ + def __iter__(self): ... + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + @base_value.setter + def base_value(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + @base_sum.setter + def base_sum(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_time(self): ... + @base_time.setter + def base_time(self, value) -> None: ... + def _check_value_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def from_json(self, data) -> None: + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + def _process_incomming_data(self, records, naming_map) -> None: + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + def do_actuate(self, raw, naming_map, device=None) -> None: + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + def from_cbor(self, data) -> None: + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + def add(self, item) -> None: + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + def remove(self, item) -> None: + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + def clear(self) -> None: + """ + clear the list of the pack + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_record.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_record.py new file mode 100644 index 000000000..b5b07b0bc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_record.py @@ -0,0 +1,240 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import binascii +from senml.senml_base import SenmlBase + + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + def __init__(self, name, **kwargs): + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + self.__parent = None # using double __ cause it's a field for an internal property + self._unit = None # declare and init internal fields + self._value = None + self._time = None + self._sum = None + self._update_time = None + + self._parent = None # internal reference to the parent object + self.name = name + self.unit = kwargs.get("unit", None) + self.value = kwargs.get("value", None) + self.time = kwargs.get("time", None) + self.sum = kwargs.get("sum", None) + self.update_time = kwargs.get("update_time", None) + self.actuate = kwargs.get("callback", None) # actuate callback function + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + def _check_value_type(self, value): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not ( + isinstance(value, bool) + or isinstance(value, int) + or isinstance(value, float) + or isinstance(value, bytearray) + or isinstance(value, str) + ): + raise Exception("invalid type for value, only numbers, strings, boolean and byte arrays allowed") + + def _check_number_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + @property + def value(self): + """get the value currently assigned to the object""" + return self._value + + @value.setter + def value(self, value): + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + self._check_value_type(value) + self._value = value + + @property + def time(self): + return self._time + + @time.setter + def time(self, value): + self._check_number_type(value, "time") + self._time = value + + @property + def update_time(self): + return self._update_time + + @update_time.setter + def update_time(self, value): + self._check_number_type(value, "update_time") + self._update_time = value + + @property + def sum(self): + return self._sum + + @sum.setter + def sum(self, value): + self._check_number_type(value, "sum") + self._sum = value + + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + return self.__parent + + @_parent.setter + def _parent(self, value): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + self.__parent = value + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + result = {} + + if self.name: + result[naming_map["n"]] = self.name + + if self._sum: + if self._parent and self._parent.base_sum: + result[naming_map["s"]] = self._sum - self._parent.base_sum + else: + result[naming_map["s"]] = self._sum + elif isinstance(self._value, bool): + result[naming_map["vb"]] = self._value + elif isinstance(self._value, int) or isinstance(self._value, float): + if self._parent and self._parent.base_value: + result[naming_map["v"]] = self._value - self._parent.base_value + else: + result[naming_map["v"]] = self._value + elif isinstance(self._value, str): + result[naming_map["vs"]] = self._value + elif isinstance(self._value, bytearray): + if naming_map["vd"] == "vd": # neeed to make a distinction between json (needs base64) and cbor (needs binary) + result[naming_map["vd"]] = binascii.b2a_base64(self._value, newline=False).decode("utf8") + else: + result[naming_map["vd"]] = self._value + else: + raise Exception("sum or value of type bootl, number, string or byte-array is required") + + if self._time: + if self._parent and self._parent.base_time: + result[naming_map["t"]] = self._time - self._parent.base_time + else: + result[naming_map["t"]] = self._time + + if self.unit: + result[naming_map["u"]] = self.unit + + if self._update_time: + if self._parent and self._parent.base_time: + result[naming_map["ut"]] = self._update_time - self._parent.base_time + else: + result[naming_map["ut"]] = self._update_time + + appendTo.append(result) + + def _from_raw(self, raw, naming_map): + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + if naming_map["v"] in raw: + val = raw[naming_map["v"]] + if self._parent and self._parent.base_value: + val += self._parent.base_value + elif naming_map["vs"] in raw: + val = raw[naming_map["vs"]] + elif naming_map["vb"] in raw: + val = raw[naming_map["vb"]] + elif naming_map["vd"] in raw: + val = binascii.a2b_base64(raw[naming_map["vb"]]) + else: + val = None + self.value = val + + def do_actuate(self, raw, naming_map): + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ + self._from_raw(raw, naming_map) + if self.actuate: + self.actuate(self) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_record.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_record.pyi new file mode 100644 index 000000000..61c0c7c05 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_record.pyi @@ -0,0 +1,104 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + __parent: Incomplete + _unit: Incomplete + _value: Incomplete + _time: Incomplete + _sum: Incomplete + _update_time: Incomplete + name: Incomplete + unit: Incomplete + actuate: Incomplete + def __init__(self, name, **kwargs) -> None: + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + def _check_value_type(self, value) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def _check_number_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + @property + def value(self): + """get the value currently assigned to the object""" + @value.setter + def value(self, value) -> None: + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + @property + def time(self): ... + @time.setter + def time(self, value) -> None: ... + @property + def update_time(self): ... + @update_time.setter + def update_time(self, value) -> None: ... + @property + def sum(self): ... + @sum.setter + def sum(self, value) -> None: ... + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + @_parent.setter + def _parent(self, value) -> None: + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + def _from_raw(self, raw, naming_map) -> None: + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + def do_actuate(self, raw, naming_map) -> None: + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_unit.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_unit.py new file mode 100644 index 000000000..bf7753c4d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_unit.py @@ -0,0 +1,89 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +def enum(**enums): + return type("Enum", (), enums) + + +SenmlUnits = enum( + SENML_UNIT_METER="m", + SENML_UNIT_KILOGRAM="kg", + SENML_UNIT_GRAM="g", + SENML_UNIT_SECOND="s", + SENML_UNIT_AMPERE="A", + SENML_UNIT_KELVIN="K", + SENML_UNIT_CANDELA="cd", + SENML_UNIT_MOLE="mol", + SENML_UNIT_HERTZ="Hz", + SENML_UNIT_RADIAN="rad", + SENML_UNIT_STERADIAN="sr", + SENML_UNIT_NEWTON="N", + SENML_UNIT_PASCAL="Pa", + SENML_UNIT_JOULE="J", + SENML_UNIT_WATT="W", + SENML_UNIT_COULOMB="C", + SENML_UNIT_VOLT="V", + SENML_UNIT_FARAD="F", + SENML_UNIT_OHM="Ohm", + SENML_UNIT_SIEMENS="S", + SENML_UNIT_WEBER="Wb", + SENML_UNIT_TESLA="T", + SENML_UNIT_HENRY="H", + SENML_UNIT_DEGREES_CELSIUS="Cel", + SENML_UNIT_LUMEN="lm", + SENML_UNIT_LUX="lx", + SENML_UNIT_BECQUEREL="Bq", + SENML_UNIT_GRAY="Gy", + SENML_UNIT_SIEVERT="Sv", + SENML_UNIT_KATAL="kat", + SENML_UNIT_SQUARE_METER="m2", + SENML_UNIT_CUBIC_METER="m3", + SENML_UNIT_LITER="l", + SENML_UNIT_VELOCITY="m/s", + SENML_UNIT_ACCELERATION="m/s2", + SENML_UNIT_CUBIC_METER_PER_SECOND="m3/s", + SENML_UNIT_LITER_PER_SECOND="l/s", + SENML_UNIT_WATT_PER_SQUARE_METER="W/m2", + SENML_UNIT_CANDELA_PER_SQUARE_METER="cd/m2", + SENML_UNIT_BIT="bit", + SENML_UNIT_BIT_PER_SECOND="bit/s", + SENML_UNIT_DEGREES_LATITUDE="lat", + SENML_UNIT_DEGREES_LONGITUDE="lon", + SENML_UNIT_PH="pH", + SENML_UNIT_DECIBEL="db", + SENML_UNIT_DECIBEL_RELATIVE_TO_1_W="dBW", + SENML_UNIT_BEL="Bspl", + SENML_UNIT_COUNTER="count", + SENML_UNIT_RATIO="//", + SENML_UNIT_RELATIVE_HUMIDITY="%RH", + SENML_UNIT_PERCENTAGE_REMAINING_BATTERY_LEVEL="%EL", + SENML_UNIT_SECONDS_REMAINING_BATTERY_LEVEL="EL", + SENML_UNIT_EVENT_RATE_PER_SECOND="1/s", + SENML_UNIT_EVENT_RATE_PER_MINUTE="1/min", + SENML_UNIT_BPM="beat/min", + SENML_UNIT_BEATS="beats", + SENML_UNIT_SIEMENS_PER_METER="S/m", +) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_unit.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_unit.pyi new file mode 100644 index 000000000..6b3e7ae68 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/senml/senml_unit.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +def enum(**enums): ... + +SenmlUnits: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/time.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/time.py new file mode 100644 index 000000000..f79ab8a3b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/time.py @@ -0,0 +1,79 @@ +from utime import * +from micropython import const + +_TS_YEAR = 0 +_TS_MON = 1 +_TS_MDAY = 2 +_TS_HOUR = 3 +_TS_MIN = 4 +_TS_SEC = 5 +_TS_WDAY = 6 +_TS_YDAY = 7 +_TS_ISDST = 8 + +_WDAY = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") +_MDAY = const( + ( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ) +) + + +def strftime(datefmt, ts): + from io import StringIO + + fmtsp = False + ftime = StringIO() + for k in datefmt: + if fmtsp: + if k == "a": + ftime.write(_WDAY[ts[_TS_WDAY]][0:3]) + elif k == "A": + ftime.write(_WDAY[ts[_TS_WDAY]]) + elif k == "b": + ftime.write(_MDAY[ts[_TS_MON] - 1][0:3]) + elif k == "B": + ftime.write(_MDAY[ts[_TS_MON] - 1]) + elif k == "d": + ftime.write("%02d" % ts[_TS_MDAY]) + elif k == "H": + ftime.write("%02d" % ts[_TS_HOUR]) + elif k == "I": + ftime.write("%02d" % (ts[_TS_HOUR] % 12)) + elif k == "j": + ftime.write("%03d" % ts[_TS_YDAY]) + elif k == "m": + ftime.write("%02d" % ts[_TS_MON]) + elif k == "M": + ftime.write("%02d" % ts[_TS_MIN]) + elif k == "P": + ftime.write("AM" if ts[_TS_HOUR] < 12 else "PM") + elif k == "S": + ftime.write("%02d" % ts[_TS_SEC]) + elif k == "w": + ftime.write(str(ts[_TS_WDAY])) + elif k == "y": + ftime.write("%02d" % (ts[_TS_YEAR] % 100)) + elif k == "Y": + ftime.write(str(ts[_TS_YEAR])) + else: + ftime.write(k) + fmtsp = False + elif k == "%": + fmtsp = True + else: + ftime.write(k) + val = ftime.getvalue() + ftime.close() + return val diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/time.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/time.pyi new file mode 100644 index 000000000..26b0e4b08 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/time.pyi @@ -0,0 +1,59 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. +""" + +from __future__ import annotations +from utime import * +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TS_YEAR: int +_TS_MON: int +_TS_MDAY: int +_TS_HOUR: int +_TS_MIN: int +_TS_SEC: int +_TS_WDAY: int +_TS_YDAY: int +_TS_ISDST: int +_WDAY: Incomplete +_MDAY: Incomplete +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def strftime(datefmt, ts): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/ARDUINO_NANO_RP2040_CONNECT/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/modules.json new file mode 100644 index 000000000..93a9baea9 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/modules.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "GENERIC", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/board.py b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/board.py new file mode 100644 index 000000000..9ee8cc806 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/board.py @@ -0,0 +1,7 @@ +from machine import Pin, Signal + +led_red = Signal("LED_RED", Pin.OUT, invert=True, value=0) +led_green = Signal("LED_GREEN", Pin.OUT, invert=True, value=0) +led_blue = Signal("LED_BLUE", Pin.OUT, invert=True, value=0) + +del Pin diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/board.pyi b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/board.pyi new file mode 100644 index 000000000..5af10af43 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/board.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +led_red: Incomplete +led_green: Incomplete +led_blue: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/modules.json new file mode 100644 index 000000000..4f3c91d73 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/modules.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "NULLBITS_BIT_C_PRO", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "board.py", + "module": "board" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/NULLBITS_BIT_C_PRO/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/central.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/client.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/core.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/device.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/security.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/server.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/modules.json new file mode 100644 index 000000000..5e44ffa00 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/modules.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "RPI_PICO2_W", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO2_W/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/central.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/client.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/core.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/device.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/security.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/server.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/modules.json new file mode 100644 index 000000000..61ec5f626 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/modules.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "RPI_PICO_W", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/RPI_PICO_W/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/modules.json new file mode 100644 index 000000000..876d6af2d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/modules.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "SIL_RP2040_SHIM", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SIL_RP2040_SHIM/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/modules.json new file mode 100644 index 000000000..90d0b4e17 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/modules.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "SPARKFUN_IOTNODE_LORAWAN_RP2350", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "sdcard.py", + "module": "sdcard" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/sdcard.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/sdcard.py new file mode 100644 index 000000000..1a271b537 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/sdcard.py @@ -0,0 +1,306 @@ +""" +MicroPython driver for SD cards using SPI bus. + +Requires an SPI bus and a CS pin. Provides readblocks and writeblocks +methods so the device can be mounted as a filesystem. + +Example usage on pyboard: + + import pyb, sdcard, os + sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) + pyb.mount(sd, '/sd2') + os.listdir('/') + +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) + os.mount(sd, '/sd') + os.listdir('/') + +""" + +from micropython import const +import time + + +_CMD_TIMEOUT = 100 + +_R1_IDLE_STATE = 1 << 0 +# R1_ERASE_RESET = 1 << 1 +_R1_ILLEGAL_COMMAND = 1 << 2 +# R1_COM_CRC_ERROR = 1 << 3 +# R1_ERASE_SEQUENCE_ERROR = 1 << 4 +# R1_ADDRESS_ERROR = 1 << 5 +# R1_PARAMETER_ERROR = 1 << 6 +_TOKEN_CMD25 = 0xFC +_TOKEN_STOP_TRAN = 0xFD +_TOKEN_DATA = 0xFE + + +class SDCard: + def __init__(self, spi, cs, baudrate=1320000): + self.spi = spi + self.cs = cs + + self.cmdbuf = bytearray(6) + self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) + for i in range(512): + self.dummybuf[i] = 0xFF + self.dummybuf_memoryview = memoryview(self.dummybuf) + + # initialise the card + self.init_card(baudrate) + + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + + def init_card(self, baudrate): + # init CS pin + self.cs.init(self.cs.OUT, value=1) + + # init SPI bus; use low data rate for initialisation + self.init_spi(100000) + + # clock card at least 100 cycles with cs high + for i in range(16): + self.spi.write(b"\xff") + + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) + for _ in range(5): + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: + break + else: + raise OSError("no SD card") + + # CMD8: determine card version + r = self.cmd(8, 0x01AA, 0x87, 4) + if r == _R1_IDLE_STATE: + self.init_card_v2() + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): + self.init_card_v1() + else: + raise OSError("couldn't determine SD card version") + + # get the number of sectors + # CMD9: response R2 (R1 byte + 16-byte block read) + if self.cmd(9, 0, 0, 0, False) != 0: + raise OSError("no response from SD card") + csd = bytearray(16) + self.readinto(csd) + if csd[0] & 0xC0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 + elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 + c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 + read_bl_len = csd[5] & 0b1111 + capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) + self.sectors = capacity // 512 + else: + raise OSError("SD card CSD format not supported") + # print('sectors', self.sectors) + + # CMD16: set block length to 512 bytes + if self.cmd(16, 512, 0) != 0: + raise OSError("can't set 512 block size") + + # set to high data rate now that it's initialised + self.init_spi(baudrate) + + def init_card_v1(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(55, 0, 0) + if self.cmd(41, 0, 0) == 0: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + # print("[SDCard] v1 card") + return + raise OSError("timeout waiting for v1 card") + + def init_card_v2(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(58, 0, 0, 4) + self.cmd(55, 0, 0) + if self.cmd(41, 0x40000000, 0) == 0: + self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte + ocr = self.tokenbuf[0] # get first byte of response, which is OCR + if not ocr & 0x40: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + else: + # SDHC/SDXC card, uses block addressing in read/write/erase commands + self.cdv = 1 + # print("[SDCard] v2 card") + return + raise OSError("timeout waiting for v2 card") + + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): + self.cs(0) + + # create and send the command + buf = self.cmdbuf + buf[0] = 0x40 | cmd + buf[1] = arg >> 24 + buf[2] = arg >> 16 + buf[3] = arg >> 8 + buf[4] = arg + buf[5] = crc + self.spi.write(buf) + + if skip1: + self.spi.readinto(self.tokenbuf, 0xFF) + + # wait for the response (response[7] == 0) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + response = self.tokenbuf[0] + if not (response & 0x80): + # this could be a big-endian integer that we are getting here + # if final<0 then store the first byte to tokenbuf and discard the rest + if final < 0: + self.spi.readinto(self.tokenbuf, 0xFF) + final = -1 - final + for j in range(final): + self.spi.write(b"\xff") + if release: + self.cs(1) + self.spi.write(b"\xff") + return response + + # timeout + self.cs(1) + self.spi.write(b"\xff") + return -1 + + def readinto(self, buf): + self.cs(0) + + # read until start byte (0xff) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + if self.tokenbuf[0] == _TOKEN_DATA: + break + time.sleep_ms(1) + else: + self.cs(1) + raise OSError("timeout waiting for response") + + # read data + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[: len(buf)] + self.spi.write_readinto(mv, buf) + + # read checksum + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + self.cs(1) + self.spi.write(b"\xff") + + def write(self, token, buf): + self.cs(0) + + # send: start of block, data, checksum + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + # check the response + if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: + self.cs(1) + self.spi.write(b"\xff") + return + + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def write_token(self, token): + self.cs(0) + self.spi.read(1, token) + self.spi.write(b"\xff") + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0x00: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def readblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, "Buffer length is invalid" + if nblocks == 1: + # CMD17: set read address for single block + if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + # receive the data and release card + self.readinto(buf) + else: + # CMD18: set read address for multiple blocks + if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + offset = 0 + mv = memoryview(buf) + while nblocks: + # receive the data and release card + self.readinto(mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + if self.cmd(12, 0, 0xFF, skip1=True): + raise OSError(5) # EIO + + def writeblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks, err = divmod(len(buf), 512) + assert nblocks and not err, "Buffer length is invalid" + if nblocks == 1: + # CMD24: set write address for single block + if self.cmd(24, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + + # send the data + self.write(_TOKEN_DATA, buf) + else: + # CMD25: set write address for first block + if self.cmd(25, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + # send the data + offset = 0 + mv = memoryview(buf) + while nblocks: + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return self.sectors + if op == 5: # get block size in bytes + return 512 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/sdcard.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/sdcard.pyi new file mode 100644 index 000000000..3009717c8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTNODE_LORAWAN_RP2350/sdcard.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CMD_TIMEOUT: int +_R1_IDLE_STATE: Incomplete +_R1_ILLEGAL_COMMAND: Incomplete +_TOKEN_CMD25: int +_TOKEN_STOP_TRAN: int +_TOKEN_DATA: int + +class SDCard: + spi: Incomplete + cs: Incomplete + cmdbuf: Incomplete + dummybuf: Incomplete + tokenbuf: Incomplete + dummybuf_memoryview: Incomplete + def __init__(self, spi, cs, baudrate: int = 1320000) -> None: ... + def init_spi(self, baudrate) -> None: ... + sectors: Incomplete + def init_card(self, baudrate) -> None: ... + cdv: int + def init_card_v1(self) -> None: ... + def init_card_v2(self) -> None: ... + def cmd(self, cmd, arg, crc, final: int = 0, release: bool = True, skip1: bool = False): ... + def readinto(self, buf) -> None: ... + def write(self, token, buf) -> None: ... + def write_token(self, token) -> None: ... + def readblocks(self, block_num, buf) -> None: ... + def writeblocks(self, block_num, buf) -> None: ... + def ioctl(self, op, arg): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/central.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/client.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/core.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/device.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/security.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/server.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/modules.json new file mode 100644 index 000000000..eeb1162d9 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/modules.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "SPARKFUN_IOTREDBOARD_RP2350", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "sdcard.py", + "module": "sdcard" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/sdcard.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/sdcard.py new file mode 100644 index 000000000..1a271b537 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/sdcard.py @@ -0,0 +1,306 @@ +""" +MicroPython driver for SD cards using SPI bus. + +Requires an SPI bus and a CS pin. Provides readblocks and writeblocks +methods so the device can be mounted as a filesystem. + +Example usage on pyboard: + + import pyb, sdcard, os + sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) + pyb.mount(sd, '/sd2') + os.listdir('/') + +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) + os.mount(sd, '/sd') + os.listdir('/') + +""" + +from micropython import const +import time + + +_CMD_TIMEOUT = 100 + +_R1_IDLE_STATE = 1 << 0 +# R1_ERASE_RESET = 1 << 1 +_R1_ILLEGAL_COMMAND = 1 << 2 +# R1_COM_CRC_ERROR = 1 << 3 +# R1_ERASE_SEQUENCE_ERROR = 1 << 4 +# R1_ADDRESS_ERROR = 1 << 5 +# R1_PARAMETER_ERROR = 1 << 6 +_TOKEN_CMD25 = 0xFC +_TOKEN_STOP_TRAN = 0xFD +_TOKEN_DATA = 0xFE + + +class SDCard: + def __init__(self, spi, cs, baudrate=1320000): + self.spi = spi + self.cs = cs + + self.cmdbuf = bytearray(6) + self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) + for i in range(512): + self.dummybuf[i] = 0xFF + self.dummybuf_memoryview = memoryview(self.dummybuf) + + # initialise the card + self.init_card(baudrate) + + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + + def init_card(self, baudrate): + # init CS pin + self.cs.init(self.cs.OUT, value=1) + + # init SPI bus; use low data rate for initialisation + self.init_spi(100000) + + # clock card at least 100 cycles with cs high + for i in range(16): + self.spi.write(b"\xff") + + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) + for _ in range(5): + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: + break + else: + raise OSError("no SD card") + + # CMD8: determine card version + r = self.cmd(8, 0x01AA, 0x87, 4) + if r == _R1_IDLE_STATE: + self.init_card_v2() + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): + self.init_card_v1() + else: + raise OSError("couldn't determine SD card version") + + # get the number of sectors + # CMD9: response R2 (R1 byte + 16-byte block read) + if self.cmd(9, 0, 0, 0, False) != 0: + raise OSError("no response from SD card") + csd = bytearray(16) + self.readinto(csd) + if csd[0] & 0xC0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 + elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6 + c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7 + read_bl_len = csd[5] & 0b1111 + capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len) + self.sectors = capacity // 512 + else: + raise OSError("SD card CSD format not supported") + # print('sectors', self.sectors) + + # CMD16: set block length to 512 bytes + if self.cmd(16, 512, 0) != 0: + raise OSError("can't set 512 block size") + + # set to high data rate now that it's initialised + self.init_spi(baudrate) + + def init_card_v1(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(55, 0, 0) + if self.cmd(41, 0, 0) == 0: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + # print("[SDCard] v1 card") + return + raise OSError("timeout waiting for v1 card") + + def init_card_v2(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(58, 0, 0, 4) + self.cmd(55, 0, 0) + if self.cmd(41, 0x40000000, 0) == 0: + self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte + ocr = self.tokenbuf[0] # get first byte of response, which is OCR + if not ocr & 0x40: + # SDSC card, uses byte addressing in read/write/erase commands + self.cdv = 512 + else: + # SDHC/SDXC card, uses block addressing in read/write/erase commands + self.cdv = 1 + # print("[SDCard] v2 card") + return + raise OSError("timeout waiting for v2 card") + + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): + self.cs(0) + + # create and send the command + buf = self.cmdbuf + buf[0] = 0x40 | cmd + buf[1] = arg >> 24 + buf[2] = arg >> 16 + buf[3] = arg >> 8 + buf[4] = arg + buf[5] = crc + self.spi.write(buf) + + if skip1: + self.spi.readinto(self.tokenbuf, 0xFF) + + # wait for the response (response[7] == 0) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + response = self.tokenbuf[0] + if not (response & 0x80): + # this could be a big-endian integer that we are getting here + # if final<0 then store the first byte to tokenbuf and discard the rest + if final < 0: + self.spi.readinto(self.tokenbuf, 0xFF) + final = -1 - final + for j in range(final): + self.spi.write(b"\xff") + if release: + self.cs(1) + self.spi.write(b"\xff") + return response + + # timeout + self.cs(1) + self.spi.write(b"\xff") + return -1 + + def readinto(self, buf): + self.cs(0) + + # read until start byte (0xff) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xFF) + if self.tokenbuf[0] == _TOKEN_DATA: + break + time.sleep_ms(1) + else: + self.cs(1) + raise OSError("timeout waiting for response") + + # read data + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[: len(buf)] + self.spi.write_readinto(mv, buf) + + # read checksum + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + self.cs(1) + self.spi.write(b"\xff") + + def write(self, token, buf): + self.cs(0) + + # send: start of block, data, checksum + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b"\xff") + self.spi.write(b"\xff") + + # check the response + if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: + self.cs(1) + self.spi.write(b"\xff") + return + + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def write_token(self, token): + self.cs(0) + self.spi.read(1, token) + self.spi.write(b"\xff") + # wait for write to finish + while self.spi.read(1, 0xFF)[0] == 0x00: + pass + + self.cs(1) + self.spi.write(b"\xff") + + def readblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, "Buffer length is invalid" + if nblocks == 1: + # CMD17: set read address for single block + if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + # receive the data and release card + self.readinto(buf) + else: + # CMD18: set read address for multiple blocks + if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + offset = 0 + mv = memoryview(buf) + while nblocks: + # receive the data and release card + self.readinto(mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + if self.cmd(12, 0, 0xFF, skip1=True): + raise OSError(5) # EIO + + def writeblocks(self, block_num, buf): + # workaround for shared bus, required for (at least) some Kingston + # devices, ensure MOSI is high before starting transaction + self.spi.write(b"\xff") + + nblocks, err = divmod(len(buf), 512) + assert nblocks and not err, "Buffer length is invalid" + if nblocks == 1: + # CMD24: set write address for single block + if self.cmd(24, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + + # send the data + self.write(_TOKEN_DATA, buf) + else: + # CMD25: set write address for first block + if self.cmd(25, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + # send the data + offset = 0 + mv = memoryview(buf) + while nblocks: + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return self.sectors + if op == 5: # get block size in bytes + return 512 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/sdcard.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/sdcard.pyi new file mode 100644 index 000000000..3009717c8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/sdcard.pyi @@ -0,0 +1,31 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CMD_TIMEOUT: int +_R1_IDLE_STATE: Incomplete +_R1_ILLEGAL_COMMAND: Incomplete +_TOKEN_CMD25: int +_TOKEN_STOP_TRAN: int +_TOKEN_DATA: int + +class SDCard: + spi: Incomplete + cs: Incomplete + cmdbuf: Incomplete + dummybuf: Incomplete + tokenbuf: Incomplete + dummybuf_memoryview: Incomplete + def __init__(self, spi, cs, baudrate: int = 1320000) -> None: ... + def init_spi(self, baudrate) -> None: ... + sectors: Incomplete + def init_card(self, baudrate) -> None: ... + cdv: int + def init_card_v1(self) -> None: ... + def init_card_v2(self) -> None: ... + def cmd(self, cmd, arg, crc, final: int = 0, release: bool = True, skip1: bool = False): ... + def readinto(self, buf) -> None: ... + def write(self, token, buf) -> None: ... + def write_token(self, token) -> None: ... + def readblocks(self, block_num, buf) -> None: ... + def writeblocks(self, block_num, buf) -> None: ... + def ioctl(self, op, arg): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_IOTREDBOARD_RP2350/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/central.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/client.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/core.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/device.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/security.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/server.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/modules.json new file mode 100644 index 000000000..c044e5bec --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/modules.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "SPARKFUN_THINGPLUS_RP2350", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_THINGPLUS_RP2350/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/central.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/client.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/core.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/device.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/security.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/server.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/modules.json new file mode 100644 index 000000000..0d5e0ae0f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/modules.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "SPARKFUN_XRP_CONTROLLER", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/central.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/client.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/core.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/device.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/security.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/server.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/modules.json new file mode 100644 index 000000000..650de768a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/modules.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "SPARKFUN_XRP_CONTROLLER_BETA", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/SPARKFUN_XRP_CONTROLLER_BETA/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/modules.json new file mode 100644 index 000000000..aa5cba85c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/modules.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "W5100S_EVB_PICO", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5100S_EVB_PICO/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/modules.json new file mode 100644 index 000000000..f21201888 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/modules.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "W5500_EVB_PICO", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ntptime.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ssl.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ssl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/urequests.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/urequests.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/W5500_EVB_PICO/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/board.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/board.py new file mode 100644 index 000000000..dd3b31b80 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/board.py @@ -0,0 +1,4 @@ +from machine import Pin + +led = Pin(25, Pin.OUT, value=0) +key = Pin(23, Pin.IN, Pin.PULL_UP) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/board.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/board.pyi new file mode 100644 index 000000000..629a051ab --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/board.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +led: Incomplete +key: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/modules.json new file mode 100644 index 000000000..6c4cd9525 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/modules.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "WEACTSTUDIO", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "board.py", + "module": "board" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot.py new file mode 100644 index 000000000..497aeb005 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot.py @@ -0,0 +1,16 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +# Note: the flash requires the programming size to be aligned to 256 bytes. +bdev = rp2.Flash() +try: + fs = vfs.VfsLfs2(bdev, progsize=256) +except: + vfs.VfsLfs2.mkfs(bdev, progsize=256) + fs = vfs.VfsLfs2(bdev, progsize=256) +vfs.mount(fs, "/") + +del vfs, bdev, fs diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot.pyi new file mode 100644 index 000000000..20aca6863 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot.pyi @@ -0,0 +1,4 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot_fat.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot_fat.py new file mode 100644 index 000000000..1b33bf13e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot_fat.py @@ -0,0 +1,14 @@ +import vfs +import machine +import rp2 + + +# Try to mount the filesystem, and format the flash if it doesn't exist. +bdev = rp2.Flash() +try: + vfs.mount(vfs.VfsFat(bdev), "/") +except: + vfs.VfsFat.mkfs(bdev) + vfs.mount(vfs.VfsFat(bdev), "/") + +del vfs, bdev diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot_fat.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot_fat.pyi new file mode 100644 index 000000000..e939f892f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/_boot_fat.pyi @@ -0,0 +1,3 @@ +from _typeshed import Incomplete + +bdev: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/dht.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/dht.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/modules.json b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/modules.json new file mode 100644 index 000000000..224b3123f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/modules.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "rp2", + "platform": "rp2", + "machine": "WEACTSTUDIO_RP2350B_CORE", + "firmware": "micropython-rp2-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "_boot_fat.py", + "module": "_boot_fat" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "neopixel.py", + "module": "neopixel" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.py new file mode 100644 index 000000000..771a4651a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.py @@ -0,0 +1,46 @@ +# NeoPixel driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared + +from machine import bitstream + + +class NeoPixel: + # G R B W + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=1): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + # Timing arg can either be 1 for 800kHz or 0 for 400kHz, + # or a user-specified timing ns tuple (high_0, low_0, high_1, low_1). + self.timing = ((400, 850, 800, 450) if timing else (800, 1700, 1600, 900)) if isinstance(timing, int) else timing + + def __len__(self): + return self.n + + def __setitem__(self, i, v): + offset = i * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = v[i] + + def __getitem__(self, i): + offset = i * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] for i in range(self.bpp)) + + def fill(self, v): + b = self.buf + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): + c = v[i] + j = self.ORDER[i] + while j < l: + b[j] = c + j += bpp + + def write(self): + # BITSTREAM_TYPE_HIGH_LOW = 0 + bitstream(self.pin, 0, self.timing, self.buf) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.pyi new file mode 100644 index 000000000..fd4de9ba0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/neopixel.pyi @@ -0,0 +1,86 @@ +""" +Control of WS2812 / NeoPixel LEDs. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/neopixel.html + +This module provides a driver for WS2818 / NeoPixel LEDs. + +``Note:`` This module is only included by default on the ESP8266, ESP32 and RP2 + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from :term:`micropython-lib` and copy it to the filesystem. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _NeoPixelBase +from machine import Pin +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_Color: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +class NeoPixel(_NeoPixelBase): + """ + This class stores pixel data for a WS2812 LED strip connected to a pin. The + application should set pixel data and then call :meth:`NeoPixel.write` + when it is ready to update the strip. + + For example:: + + import neopixel + + # 32 LED strip connected to X8. + p = machine.Pin.board.X8 + n = neopixel.NeoPixel(p, 32) + + # Draw a red gradient. + for i in range(32): + n[i] = (i * 8, 0, 0) + + # Update the strip. + n.write() + """ + + ORDER: Incomplete + pin: Incomplete + n: Incomplete + bpp: Incomplete + buf: Incomplete + timing: Incomplete + def __init__(self, pin, n, bpp: int = 3, timing: int = 1) -> None: + """ + Construct an NeoPixel object. The parameters are: + + - *pin* is a machine.Pin instance. + - *n* is the number of LEDs in the strip. + - *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs. + - *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz). + """ + ... + def __len__(self) -> int: + """ + Returns the number of LEDs in the strip. + """ + ... + def __setitem__(self, i, v) -> None: + """ + Set the pixel at *index* to the value, which is an RGB/RGBW tuple. + """ + ... + def __getitem__(self, i) -> Tuple: + """ + Returns the pixel at *index* as an RGB/RGBW tuple. + """ + ... + def fill(self, v) -> None: + """ + Sets the value of all pixels to the specified *pixel* value (i.e. an + RGB/RGBW tuple). + """ + ... + def write(self) -> None: + """ + Writes the current pixel data to the strip. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/onewire.py b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/onewire.pyi b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/removed.txt b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/rp2/WEACTSTUDIO_RP2350B_CORE/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/_boot.py b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/_boot.py new file mode 100644 index 000000000..f4053e2cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/_boot.py @@ -0,0 +1,21 @@ +import gc +import vfs +import samd +import sys + +bdev = samd.Flash() + +# Try to mount the filesystem, and format the flash if it doesn't exist. +fs_type = vfs.VfsLfs2 if hasattr(vfs, "VfsLfs2") else vfs.VfsLfs1 + +try: + fs = fs_type(bdev, progsize=256) +except: + fs_type.mkfs(bdev, progsize=256) + fs = fs_type(bdev, progsize=256) +vfs.mount(fs, "/") +sys.path.append("/lib") + +del fs, fs_type, bdev, vfs, samd, sys +gc.collect() +del gc diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/_boot.pyi b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/_boot.pyi new file mode 100644 index 000000000..d68628c9f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/_boot.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +bdev: Incomplete +fs_type: Incomplete +fs: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/dht.py b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/dht.pyi b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/ds18x20.py b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/ds18x20.py new file mode 100644 index 000000000..e6361dca7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/ds18x20.py @@ -0,0 +1,52 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = 0x44 +_RD_SCRATCH = 0xBE +_WR_SCRATCH = 0x4E + + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception("CRC error") + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xFF) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xFFFF) + 1) + return t / 16 diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/ds18x20.pyi b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/modules.json new file mode 100644 index 000000000..80a399973 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/modules.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "samd", + "platform": "samd", + "machine": "GENERIC", + "firmware": "micropython-samd-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "_boot.py", + "module": "_boot" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "ds18x20.py", + "module": "ds18x20" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/onewire.py b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/samd/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/samd/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/central.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/client.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/core.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/device.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/security.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/server.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/__init__.py new file mode 100644 index 000000000..80790f0da --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/__init__.py @@ -0,0 +1,32 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from ._decoder import CBORDecoder +from ._decoder import load +from ._decoder import loads + +from ._encoder import CBOREncoder +from ._encoder import dump +from ._encoder import dumps diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/__init__.pyi new file mode 100644 index 000000000..0ef59d019 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/__init__.pyi @@ -0,0 +1,2 @@ +from ._decoder import CBORDecoder as CBORDecoder, load as load, loads as loads +from ._encoder import CBOREncoder as CBOREncoder, dump as dump, dumps as dumps diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_decoder.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_decoder.py new file mode 100644 index 000000000..8434aec26 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_decoder.py @@ -0,0 +1,254 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + + +break_marker = object() + + +class CBORSimpleValue(object): + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + def __init__(self, value): + if value < 0 or value > 255: + raise TypeError("simple value too big") + self.value = value + + def __eq__(self, other): + if isinstance(other, CBORSimpleValue): + return self.value == other.value + elif isinstance(other, int): + return self.value == other + return NotImplemented + + def __repr__(self): + return "CBORSimpleValue({self.value})".format(self=self) + + +def decode_uint(decoder, subtype, allow_indefinite=False): + # Major tag 0 + if subtype < 24: + return subtype + elif subtype == 24: + return struct.unpack(">B", decoder.read(1))[0] + elif subtype == 25: + return struct.unpack(">H", decoder.read(2))[0] + elif subtype == 26: + return struct.unpack(">L", decoder.read(4))[0] + elif subtype == 27: + return struct.unpack(">Q", decoder.read(8))[0] + elif subtype == 31 and allow_indefinite: + return None + else: + raise CBORDecodeError("unknown unsigned integer subtype 0x%x" % subtype) + + +def decode_negint(decoder, subtype): + # Major tag 1 + uint = decode_uint(decoder, subtype) + return -uint - 1 + + +def decode_bytestring(decoder, subtype): + # Major tag 2 + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + buf = bytearray() + while True: + initial_byte = decoder.read(1)[0] + if initial_byte == 255: + return buf + else: + length = decode_uint(decoder, initial_byte & 31) + value = decoder.read(length) + buf.extend(value) + else: + return decoder.read(length) + + +def decode_string(decoder, subtype): + # Major tag 3 + return decode_bytestring(decoder, subtype).decode("utf-8") + + +def decode_array(decoder, subtype): + # Major tag 4 + items = [] + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + value = decoder.decode() + if value is break_marker: + break + else: + items.append(value) + else: + for _ in range(length): + item = decoder.decode() + items.append(item) + return items + + +def decode_map(decoder, subtype): + # Major tag 5 + dictionary = {} + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + key = decoder.decode() + if key is break_marker: + break + else: + value = decoder.decode() + dictionary[key] = value + else: + for _ in range(length): + key = decoder.decode() + value = decoder.decode() + dictionary[key] = value + + return dictionary + + +def decode_special(decoder, subtype): + # Simple value + if subtype < 20: + return CBORSimpleValue(subtype) + + # Major tag 7 + return special_decoders[subtype](decoder) + + +def decode_simple_value(decoder): + return CBORSimpleValue(struct.unpack(">B", decoder.read(1))[0]) + + +def decode_float16(decoder): + decoder.read(2) + raise NotImplementedError # no float16 unpack function + + +def decode_float32(decoder): + return struct.unpack(">f", decoder.read(4))[0] + + +def decode_float64(decoder): + return struct.unpack(">d", decoder.read(8))[0] + + +major_decoders = { + 0: decode_uint, + 1: decode_negint, + 2: decode_bytestring, + 3: decode_string, + 4: decode_array, + 5: decode_map, + 7: decode_special, +} + +special_decoders = { + 20: lambda self: False, + 21: lambda self: True, + 22: lambda self: None, + # 23 is undefined + 24: decode_simple_value, + 25: decode_float16, + 26: decode_float32, + 27: decode_float64, + 31: lambda self: break_marker, +} + + +class CBORDecoder(object): + """ + Deserializes a CBOR encoded byte stream. + """ + + def __init__(self, fp): + self.fp = fp + + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + data = self.fp.read(amount) + if len(data) < amount: + raise CBORDecodeError("premature end of stream (expected to read {} bytes, got {} instead)".format(amount, len(data))) + + return data + + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + try: + initial_byte = self.fp.read(1)[0] + major_type = initial_byte >> 5 + subtype = initial_byte & 31 + except Exception as e: + raise CBORDecodeError("error reading major type at index {}: {}".format(self.fp.tell(), e)) + + decoder = major_decoders[major_type] + try: + return decoder(self, subtype) + except CBORDecodeError: + raise + except Exception as e: + raise CBORDecodeError("error decoding value {}".format(e)) # tell doesn't work on micropython at the moment + + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + fp = io.BytesIO(payload) + return CBORDecoder(fp, **kwargs).decode() + + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + return CBORDecoder(fp, **kwargs).decode() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_decoder.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_decoder.pyi new file mode 100644 index 000000000..d4daffe85 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_decoder.pyi @@ -0,0 +1,66 @@ +from _typeshed import Incomplete + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + +break_marker: Incomplete + +class CBORSimpleValue: + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + value: Incomplete + def __init__(self, value) -> None: ... + def __eq__(self, other): ... + def __repr__(self) -> str: ... + +def decode_uint(decoder, subtype, allow_indefinite: bool = False): ... +def decode_negint(decoder, subtype): ... +def decode_bytestring(decoder, subtype): ... +def decode_string(decoder, subtype): ... +def decode_array(decoder, subtype): ... +def decode_map(decoder, subtype): ... +def decode_special(decoder, subtype): ... +def decode_simple_value(decoder): ... +def decode_float16(decoder) -> None: ... +def decode_float32(decoder): ... +def decode_float64(decoder): ... + +major_decoders: Incomplete +special_decoders: Incomplete + +class CBORDecoder: + """ + Deserializes a CBOR encoded byte stream. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_encoder.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_encoder.py new file mode 100644 index 000000000..fe8715468 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_encoder.py @@ -0,0 +1,182 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + + +def encode_length(major_tag, length): + if length < 24: + return struct.pack(">B", major_tag | length) + elif length < 256: + return struct.pack(">BB", major_tag | 24, length) + elif length < 65536: + return struct.pack(">BH", major_tag | 25, length) + elif length < 4294967296: + return struct.pack(">BL", major_tag | 26, length) + else: + return struct.pack(">BQ", major_tag | 27, length) + + +def encode_semantic(encoder, tag, value): + encoder.write(encode_length(0xC0, tag)) + encoder.encode(value) + + +def encode_float(encoder, value): + # Handle special values efficiently + import math + + if math.isnan(value): + encoder.write(b"\xf9\x7e\x00") + elif math.isinf(value): + encoder.write(b"\xf9\x7c\x00" if value > 0 else b"\xf9\xfc\x00") + else: + encoder.write(struct.pack(">Bd", 0xFB, value)) + + +def encode_int(encoder, value): + # Big integers (2 ** 64 and over) + if value >= 18446744073709551616 or value < -18446744073709551616: + if value >= 0: + major_type = 0x02 + else: + major_type = 0x03 + value = -value - 1 + + values = [] + while value > 0: + value, remainder = divmod(value, 256) + values.insert(0, remainder) + + payload = bytes(values) + encode_semantic(encoder, major_type, payload) + elif value >= 0: + encoder.write(encode_length(0, value)) + else: + encoder.write(encode_length(0x20, abs(value) - 1)) + + +def encode_bytestring(encoder, value): + encoder.write(encode_length(0x40, len(value)) + value) + + +def encode_bytearray(encoder, value): + encode_bytestring(encoder, bytes(value)) + + +def encode_string(encoder, value): + encoded = value.encode("utf-8") + encoder.write(encode_length(0x60, len(encoded)) + encoded) + + +def encode_map(encoder, value): + encoder.write(encode_length(0xA0, len(value))) + for key, val in value.items(): + encoder.encode(key) + encoder.encode(val) + + +def encode_array(encoder, value): + encoder.write(encode_length(0x80, len(value))) + for item in value: + encoder.encode(item) + + +def encode_boolean(encoder, value): + encoder.write(b"\xf5" if value else b"\xf4") + + +def encode_none(encoder, value): + encoder.write(b"\xf6") + + +cbor_encoders = { # supported data types and the encoder to use. + bytes: encode_bytestring, + bytearray: encode_bytearray, + str: encode_string, + int: encode_int, + float: encode_float, + bool: encode_boolean, + type(None): encode_none, + list: encode_array, + dict: encode_map, +} + + +class CBOREncoder(object): + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + def __init__(self, fp): + self.fp = fp + + def _find_encoder(self, obj): + return cbor_encoders[type(obj)] + + def write(self, data): + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + self.fp.write(data) + + def encode(self, obj): + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + encoder = self._find_encoder(obj) + if not encoder: + raise CBOREncodeError("cannot serialize type %s" % type(obj)) + encoder(self, obj) + + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + fp = io.BytesIO() + dump(obj, fp, **kwargs) + return fp.getvalue() + + +def dump(obj, fp, **kwargs): + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ + CBOREncoder(fp, **kwargs).encode(obj) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_encoder.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_encoder.pyi new file mode 100644 index 000000000..8cd761686 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/cbor2/_encoder.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + +def encode_length(major_tag, length): ... +def encode_semantic(encoder, tag, value) -> None: ... +def encode_float(encoder, value) -> None: ... +def encode_int(encoder, value) -> None: ... +def encode_bytestring(encoder, value) -> None: ... +def encode_bytearray(encoder, value) -> None: ... +def encode_string(encoder, value) -> None: ... +def encode_map(encoder, value) -> None: ... +def encode_array(encoder, value) -> None: ... +def encode_boolean(encoder, value) -> None: ... +def encode_none(encoder, value) -> None: ... + +cbor_encoders: Incomplete + +class CBOREncoder: + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def _find_encoder(self, obj): ... + def write(self, data) -> None: + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + def encode(self, obj) -> None: + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + +def dump(obj, fp, **kwargs) -> None: + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/logging.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/logging.py new file mode 100644 index 000000000..edee407c6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/logging.py @@ -0,0 +1,253 @@ +from micropython import const +import io +import sys +import time + +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 + +_DEFAULT_LEVEL = WARNING + +_level_dict = { + CRITICAL: "CRITICAL", + ERROR: "ERROR", + WARNING: "WARNING", + INFO: "INFO", + DEBUG: "DEBUG", + NOTSET: "NOTSET", +} + +_loggers = {} +_stream = sys.stderr +_default_fmt = "%(levelname)s:%(name)s:%(message)s" +_default_datefmt = "%Y-%m-%d %H:%M:%S" + + +class LogRecord: + def set(self, name, level, message): + self.name = name + self.levelno = level + self.levelname = _level_dict[level] + self.message = message + self.ct = time.time() + self.msecs = int((self.ct - int(self.ct)) * 1000) + self.asctime = None + + +class Handler: + def __init__(self, level=NOTSET): + self.level = level + self.formatter = None + + def close(self): + pass + + def setLevel(self, level): + self.level = level + + def setFormatter(self, formatter): + self.formatter = formatter + + def format(self, record): + return self.formatter.format(record) + + +class StreamHandler(Handler): + def __init__(self, stream=None): + super().__init__() + self.stream = _stream if stream is None else stream + self.terminator = "\n" + + def close(self): + if hasattr(self.stream, "flush"): + self.stream.flush() + + def emit(self, record): + if record.levelno >= self.level: + self.stream.write(self.format(record) + self.terminator) + + +class FileHandler(StreamHandler): + def __init__(self, filename, mode="a", encoding="UTF-8"): + super().__init__(stream=open(filename, mode=mode, encoding=encoding)) + + def close(self): + super().close() + self.stream.close() + + +class Formatter: + def __init__(self, fmt=None, datefmt=None): + self.fmt = _default_fmt if fmt is None else fmt + self.datefmt = _default_datefmt if datefmt is None else datefmt + + def usesTime(self): + return "asctime" in self.fmt + + def formatTime(self, datefmt, record): + if hasattr(time, "strftime"): + return time.strftime(datefmt, time.localtime(record.ct)) + return None + + def format(self, record): + if self.usesTime(): + record.asctime = self.formatTime(self.datefmt, record) + return self.fmt % { + "name": record.name, + "message": record.message, + "msecs": record.msecs, + "asctime": record.asctime, + "levelname": record.levelname, + } + + +class Logger: + def __init__(self, name, level=NOTSET): + self.name = name + self.level = level + self.handlers = [] + self.record = LogRecord() + + def setLevel(self, level): + self.level = level + + def isEnabledFor(self, level): + return level >= self.getEffectiveLevel() + + def getEffectiveLevel(self): + return self.level or getLogger().level or _DEFAULT_LEVEL + + def log(self, level, msg, *args): + if self.isEnabledFor(level): + if args: + if isinstance(args[0], dict): + args = args[0] + msg = msg % args + self.record.set(self.name, level, msg) + handlers = self.handlers + if not handlers: + handlers = getLogger().handlers + for h in handlers: + h.emit(self.record) + + def debug(self, msg, *args): + self.log(DEBUG, msg, *args) + + def info(self, msg, *args): + self.log(INFO, msg, *args) + + def warning(self, msg, *args): + self.log(WARNING, msg, *args) + + def error(self, msg, *args): + self.log(ERROR, msg, *args) + + def critical(self, msg, *args): + self.log(CRITICAL, msg, *args) + + def exception(self, msg, *args, exc_info=True): + self.log(ERROR, msg, *args) + tb = None + if isinstance(exc_info, BaseException): + tb = exc_info + elif hasattr(sys, "exc_info"): + tb = sys.exc_info()[1] + if tb: + buf = io.StringIO() + sys.print_exception(tb, buf) + self.log(ERROR, buf.getvalue()) + + def addHandler(self, handler): + self.handlers.append(handler) + + def hasHandlers(self): + return len(self.handlers) > 0 + + +def getLogger(name=None): + if name is None: + name = "root" + if name not in _loggers: + _loggers[name] = Logger(name) + if name == "root": + basicConfig() + return _loggers[name] + + +def log(level, msg, *args): + getLogger().log(level, msg, *args) + + +def debug(msg, *args): + getLogger().debug(msg, *args) + + +def info(msg, *args): + getLogger().info(msg, *args) + + +def warning(msg, *args): + getLogger().warning(msg, *args) + + +def error(msg, *args): + getLogger().error(msg, *args) + + +def critical(msg, *args): + getLogger().critical(msg, *args) + + +def exception(msg, *args, exc_info=True): + getLogger().exception(msg, *args, exc_info=exc_info) + + +def shutdown(): + for k, logger in _loggers.items(): + for h in logger.handlers: + h.close() + _loggers.pop(logger, None) + + +def addLevelName(level, name): + _level_dict[level] = name + + +def basicConfig( + filename=None, + filemode="a", + format=None, + datefmt=None, + level=WARNING, + stream=None, + encoding="UTF-8", + force=False, +): + if "root" not in _loggers: + _loggers["root"] = Logger("root") + + logger = _loggers["root"] + + if force or not logger.handlers: + for h in logger.handlers: + h.close() + logger.handlers = [] + + if filename is None: + handler = StreamHandler(stream) + else: + handler = FileHandler(filename, filemode, encoding) + + handler.setLevel(level) + handler.setFormatter(Formatter(format, datefmt)) + + logger.setLevel(level) + logger.addHandler(handler) + + +if hasattr(sys, "atexit"): + sys.atexit(shutdown) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/logging.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/logging.pyi new file mode 100644 index 000000000..856bcccf7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/logging.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete +from micropython import const as const + +CRITICAL: int +ERROR: int +WARNING: int +INFO: int +DEBUG: int +NOTSET: int +_DEFAULT_LEVEL = WARNING +_level_dict: Incomplete +_loggers: Incomplete +_stream: Incomplete +_default_fmt: str +_default_datefmt: str + +class LogRecord: + name: Incomplete + levelno: Incomplete + levelname: Incomplete + message: Incomplete + ct: Incomplete + msecs: Incomplete + asctime: Incomplete + def set(self, name, level, message) -> None: ... + +class Handler: + level: Incomplete + formatter: Incomplete + def __init__(self, level=...) -> None: ... + def close(self) -> None: ... + def setLevel(self, level) -> None: ... + def setFormatter(self, formatter) -> None: ... + def format(self, record): ... + +class StreamHandler(Handler): + stream: Incomplete + terminator: str + def __init__(self, stream=None) -> None: ... + def close(self) -> None: ... + def emit(self, record) -> None: ... + +class FileHandler(StreamHandler): + def __init__(self, filename, mode: str = "a", encoding: str = "UTF-8") -> None: ... + def close(self) -> None: ... + +class Formatter: + fmt: Incomplete + datefmt: Incomplete + def __init__(self, fmt=None, datefmt=None) -> None: ... + def usesTime(self): ... + def formatTime(self, datefmt, record): ... + def format(self, record): ... + +class Logger: + name: Incomplete + level: Incomplete + handlers: Incomplete + record: Incomplete + def __init__(self, name, level=...) -> None: ... + def setLevel(self, level) -> None: ... + def isEnabledFor(self, level): ... + def getEffectiveLevel(self): ... + def log(self, level, msg, *args) -> None: ... + def debug(self, msg, *args) -> None: ... + def info(self, msg, *args) -> None: ... + def warning(self, msg, *args) -> None: ... + def error(self, msg, *args) -> None: ... + def critical(self, msg, *args) -> None: ... + def exception(self, msg, *args, exc_info: bool = True) -> None: ... + def addHandler(self, handler) -> None: ... + def hasHandlers(self): ... + +def getLogger(name=None): ... +def log(level, msg, *args) -> None: ... +def debug(msg, *args) -> None: ... +def info(msg, *args) -> None: ... +def warning(msg, *args) -> None: ... +def error(msg, *args) -> None: ... +def critical(msg, *args) -> None: ... +def exception(msg, *args, exc_info: bool = True) -> None: ... +def shutdown() -> None: ... +def addLevelName(level, name) -> None: ... +def basicConfig( + filename=None, filemode: str = "a", format=None, datefmt=None, level=..., stream=None, encoding: str = "UTF-8", force: bool = False +) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/modules.json new file mode 100644 index 000000000..3125b3487 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/modules.json @@ -0,0 +1,140 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "ARDUINO_GIGA", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "cbor2/__init__.py", + "module": "__init__" + }, + { + "file": "cbor2/_decoder.py", + "module": "_decoder" + }, + { + "file": "cbor2/_encoder.py", + "module": "_encoder" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "logging.py", + "module": "logging" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "msgpack.py", + "module": "msgpack" + }, + { + "file": "msgpackrpc.py", + "module": "msgpackrpc" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "senml/__init__.py", + "module": "__init__" + }, + { + "file": "senml/senml_base.py", + "module": "senml_base" + }, + { + "file": "senml/senml_pack.py", + "module": "senml_pack" + }, + { + "file": "senml/senml_record.py", + "module": "senml_record" + }, + { + "file": "senml/senml_unit.py", + "module": "senml_unit" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "time.py", + "module": "time" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpack.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpack.py new file mode 100644 index 000000000..3f1f2683c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpack.py @@ -0,0 +1,860 @@ +# u-msgpack-python v2.8.0 - v at sergeev.io +# https://github.com/vsergeev/u-msgpack-python +# +# u-msgpack-python is a lightweight MessagePack serializer and deserializer +# module, compatible with both Python 2 and 3, as well CPython and PyPy +# implementations of Python. u-msgpack-python is fully compliant with the +# latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +# particular, it supports the new binary, UTF-8 string, and application ext +# types. +# +# MIT License +# +# Copyright (c) 2013-2023 vsergeev / Ivan (Vanya) A. Sergeev +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +""" +u-msgpack-python v2.8.0 - v at sergeev.io +https://github.com/vsergeev/u-msgpack-python + +u-msgpack-python is a lightweight MessagePack serializer and deserializer +module, compatible with both Python 2 and 3, as well CPython and PyPy +implementations of Python. u-msgpack-python is fully compliant with the +latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +particular, it supports the new binary, UTF-8 string, and application ext +types. + +License: MIT +""" + +import struct +import collections +import sys +import io + +__version__ = "2.8.0" +"Module version string" + +version = (2, 8, 0) +"Module version tuple" + + +############################################################################## +# Ext Class +############################################################################## + + +# Extension type for application-defined types and data +class Ext(object): + """ + The Ext class facilitates creating a serializable extension object to store + an application-defined type and data byte array. + """ + + def __init__(self, type, data): + """ + Construct a new Ext object. + + Args: + type (int): application-defined type integer + data (bytes): application-defined data byte array + + Raises: + TypeError: + Type is not an integer. + ValueError: + Type is out of range of -128 to 127. + TypeError: + Data is not type 'bytes' (Python 3) or not type 'str' (Python 2). + + Example: + >>> foo = umsgpack.Ext(5, b"\\x01\\x02\\x03") + >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) + '\\x82\\xa7awesome\\xc3\\xadspecial stuff\\xc7\\x03\\x05\\x01\\x02\\x03' + >>> bar = umsgpack.unpackb(_) + >>> print(bar["special stuff"]) + Ext Object (Type: 5, Data: 01 02 03) + """ + # Check type is type int and in range + if not isinstance(type, int): + raise TypeError("ext type is not type integer") + elif not (-(2**7) <= type <= 2**7 - 1): + raise ValueError("ext type value {:d} is out of range (-128 to 127)".format(type)) + # Check data is type bytes or str + elif sys.version_info[0] == 3 and not isinstance(data, bytes): + raise TypeError("ext data is not type 'bytes'") + elif sys.version_info[0] == 2 and not isinstance(data, str): + raise TypeError("ext data is not type 'str'") + + self.type = type + self.data = data + + def __eq__(self, other): + """ + Compare this Ext object with another for equality. + """ + return isinstance(other, self.__class__) and self.type == other.type and self.data == other.data + + def __ne__(self, other): + """ + Compare this Ext object with another for inequality. + """ + return not self.__eq__(other) + + def __str__(self): + """ + String representation of this Ext object. + """ + s = "Ext Object (Type: {:d}, Data: ".format(self.type) + s += " ".join(["0x{:02x}".format(ord(self.data[i : i + 1])) for i in range(min(len(self.data), 8))]) + if len(self.data) > 8: + s += " ..." + s += ")" + return s + + def __hash__(self): + """ + Provide a hash of this Ext object. + """ + return hash((self.type, self.data)) + + +class InvalidString(bytes): + """Subclass of bytes to hold invalid UTF-8 strings.""" + + +############################################################################## +# Ext Serializable Decorator +############################################################################## + +_ext_class_to_type = {} +_ext_type_to_class = {} + + +def ext_serializable(ext_type): + """ + Return a decorator to register a class for automatic packing and unpacking + with the specified Ext type code. The application class should implement a + `packb()` method that returns serialized bytes, and an `unpackb()` class + method or static method that accepts serialized bytes and returns an + instance of the application class. + + Args: + ext_type (int): application-defined Ext type code + + Raises: + TypeError: + Ext type is not an integer. + ValueError: + Ext type is out of range of -128 to 127. + ValueError: + Ext type or class already registered. + """ + + def wrapper(cls): + if not isinstance(ext_type, int): + raise TypeError("Ext type is not type integer") + elif not (-(2**7) <= ext_type <= 2**7 - 1): + raise ValueError("Ext type value {:d} is out of range of -128 to 127".format(ext_type)) + elif ext_type in _ext_type_to_class: + raise ValueError("Ext type {:d} already registered with class {:s}".format(ext_type, repr(_ext_type_to_class[ext_type]))) + elif cls in _ext_class_to_type: + raise ValueError("Class {:s} already registered with Ext type {:d}".format(repr(cls), ext_type)) + + _ext_type_to_class[ext_type] = cls + _ext_class_to_type[cls] = ext_type + + return cls + + return wrapper + + +############################################################################## +# Exceptions +############################################################################## + + +# Base Exception classes +class PackException(Exception): + "Base class for exceptions encountered during packing." + + +class UnpackException(Exception): + "Base class for exceptions encountered during unpacking." + + +# Packing error +class UnsupportedTypeException(PackException): + "Object type not supported for packing." + + +# Unpacking error +class InsufficientDataException(UnpackException): + "Insufficient data to unpack the serialized object." + + +class InvalidStringException(UnpackException): + "Invalid UTF-8 string encountered during unpacking." + + +class UnsupportedTimestampException(UnpackException): + "Unsupported timestamp format encountered during unpacking." + + +class ReservedCodeException(UnpackException): + "Reserved code encountered during unpacking." + + +class UnhashableKeyException(UnpackException): + """ + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + """ + + +class DuplicateKeyException(UnpackException): + "Duplicate key encountered during map unpacking." + + +############################################################################## +# Packing +############################################################################## + +# You may notice struct.pack("B", obj) instead of the simpler chr(obj) in the +# code below. This is to allow for seamless Python 2 and 3 compatibility, as +# chr(obj) has a str return type instead of bytes in Python 3, and +# struct.pack(...) has the right return type in both versions. + + +def _pack_integer(obj, fp, options): + if obj < 0: + if obj >= -32: + fp.write(struct.pack("b", obj)) + elif obj >= -(2 ** (8 - 1)): + fp.write(b"\xd0" + struct.pack("b", obj)) + elif obj >= -(2 ** (16 - 1)): + fp.write(b"\xd1" + struct.pack(">h", obj)) + elif obj >= -(2 ** (32 - 1)): + fp.write(b"\xd2" + struct.pack(">i", obj)) + elif obj >= -(2 ** (64 - 1)): + fp.write(b"\xd3" + struct.pack(">q", obj)) + else: + raise UnsupportedTypeException("huge signed int") + else: + if obj < 128: + fp.write(struct.pack("B", obj)) + elif obj < 2**8: + fp.write(b"\xcc" + struct.pack("B", obj)) + elif obj < 2**16: + fp.write(b"\xcd" + struct.pack(">H", obj)) + elif obj < 2**32: + fp.write(b"\xce" + struct.pack(">I", obj)) + elif obj < 2**64: + fp.write(b"\xcf" + struct.pack(">Q", obj)) + else: + raise UnsupportedTypeException("huge unsigned int") + + +def _pack_nil(obj, fp, options): + fp.write(b"\xc0") + + +def _pack_boolean(obj, fp, options): + fp.write(b"\xc3" if obj else b"\xc2") + + +def _pack_float(obj, fp, options): + float_precision = options.get("force_float_precision", "single") + + if float_precision == "double": + fp.write(b"\xcb" + struct.pack(">d", obj)) + elif float_precision == "single": + fp.write(b"\xca" + struct.pack(">f", obj)) + else: + raise ValueError("invalid float precision") + + +def _pack_string(obj, fp, options): + obj = obj.encode("utf-8") + obj_len = len(obj) + if obj_len < 32: + fp.write(struct.pack("B", 0xA0 | obj_len) + obj) + elif obj_len < 2**8: + fp.write(b"\xd9" + struct.pack("B", obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xda" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xdb" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge string") + + +def _pack_binary(obj, fp, options): + obj_len = len(obj) + if obj_len < 2**8: + fp.write(b"\xc4" + struct.pack("B", obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xc5" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xc6" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge binary string") + + +def _pack_oldspec_raw(obj, fp, options): + obj_len = len(obj) + if obj_len < 32: + fp.write(struct.pack("B", 0xA0 | obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xda" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xdb" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge raw string") + + +def _pack_ext(obj, fp, options): + obj_len = len(obj.data) + if obj_len == 1: + fp.write(b"\xd4" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 2: + fp.write(b"\xd5" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 4: + fp.write(b"\xd6" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 8: + fp.write(b"\xd7" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 16: + fp.write(b"\xd8" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len < 2**8: + fp.write(b"\xc7" + struct.pack("BB", obj_len, obj.type & 0xFF) + obj.data) + elif obj_len < 2**16: + fp.write(b"\xc8" + struct.pack(">HB", obj_len, obj.type & 0xFF) + obj.data) + elif obj_len < 2**32: + fp.write(b"\xc9" + struct.pack(">IB", obj_len, obj.type & 0xFF) + obj.data) + else: + raise UnsupportedTypeException("huge ext data") + + +def _pack_array(obj, fp, options): + obj_len = len(obj) + if obj_len < 16: + fp.write(struct.pack("B", 0x90 | obj_len)) + elif obj_len < 2**16: + fp.write(b"\xdc" + struct.pack(">H", obj_len)) + elif obj_len < 2**32: + fp.write(b"\xdd" + struct.pack(">I", obj_len)) + else: + raise UnsupportedTypeException("huge array") + + for e in obj: + pack(e, fp, **options) + + +def _pack_map(obj, fp, options): + obj_len = len(obj) + if obj_len < 16: + fp.write(struct.pack("B", 0x80 | obj_len)) + elif obj_len < 2**16: + fp.write(b"\xde" + struct.pack(">H", obj_len)) + elif obj_len < 2**32: + fp.write(b"\xdf" + struct.pack(">I", obj_len)) + else: + raise UnsupportedTypeException("huge array") + + for k, v in obj.items(): + pack(k, fp, **options) + pack(v, fp, **options) + + +# Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type +def pack(obj, fp, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + None + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> f = open('test.bin', 'wb') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + """ + ext_handlers = options.get("ext_handlers") + + if obj is None: + _pack_nil(obj, fp, options) + elif ext_handlers and obj.__class__ in ext_handlers: + _pack_ext(ext_handlers[obj.__class__](obj), fp, options) + elif obj.__class__ in _ext_class_to_type: + try: + _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) + elif isinstance(obj, bool): + _pack_boolean(obj, fp, options) + elif isinstance(obj, int): + _pack_integer(obj, fp, options) + elif isinstance(obj, float): + _pack_float(obj, fp, options) + elif isinstance(obj, str): + _pack_string(obj, fp, options) + elif isinstance(obj, bytes): + _pack_binary(obj, fp, options) + elif isinstance(obj, (list, tuple)): + _pack_array(obj, fp, options) + elif isinstance(obj, dict): + _pack_map(obj, fp, options) + elif isinstance(obj, Ext): + _pack_ext(obj, fp, options) + elif ext_handlers: + # Linear search for superclass + t = next((t for t in ext_handlers.keys() if isinstance(obj, t)), None) + if t: + _pack_ext(ext_handlers[t](obj), fp, options) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + elif _ext_class_to_type: + # Linear search for superclass + t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) + if t: + try: + _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + + +def packb(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + bytes: Serialized MessagePack bytes + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + b'\\x82\\xa7compact\\xc3\\xa6schema\\x00' + """ + fp = io.BytesIO() + pack(obj, fp, **options) + return fp.getvalue() + + +############################################################################# +# Unpacking +############################################################################# + + +def _read_except(fp, n): + if n == 0: + return b"" + + data = fp.read(n) + if len(data) == 0: + raise InsufficientDataException() + + while len(data) < n: + chunk = fp.read(n - len(data)) + if len(chunk) == 0: + raise InsufficientDataException() + + data += chunk + + return data + + +def _unpack_integer(code, fp, options): + if (ord(code) & 0xE0) == 0xE0: + return struct.unpack("b", code)[0] + elif code == b"\xd0": + return struct.unpack("b", _read_except(fp, 1))[0] + elif code == b"\xd1": + return struct.unpack(">h", _read_except(fp, 2))[0] + elif code == b"\xd2": + return struct.unpack(">i", _read_except(fp, 4))[0] + elif code == b"\xd3": + return struct.unpack(">q", _read_except(fp, 8))[0] + elif (ord(code) & 0x80) == 0x00: + return struct.unpack("B", code)[0] + elif code == b"\xcc": + return struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xcd": + return struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xce": + return struct.unpack(">I", _read_except(fp, 4))[0] + elif code == b"\xcf": + return struct.unpack(">Q", _read_except(fp, 8))[0] + raise Exception("logic error, not int: 0x{:02x}".format(ord(code))) + + +def _unpack_reserved(code, fp, options): + if code == b"\xc1": + raise ReservedCodeException("encountered reserved code: 0x{:02x}".format(ord(code))) + raise Exception("logic error, not reserved code: 0x{:02x}".format(ord(code))) + + +def _unpack_nil(code, fp, options): + if code == b"\xc0": + return None + raise Exception("logic error, not nil: 0x{:02x}".format(ord(code))) + + +def _unpack_boolean(code, fp, options): + if code == b"\xc2": + return False + elif code == b"\xc3": + return True + raise Exception("logic error, not boolean: 0x{:02x}".format(ord(code))) + + +def _unpack_float(code, fp, options): + if code == b"\xca": + return struct.unpack(">f", _read_except(fp, 4))[0] + elif code == b"\xcb": + return struct.unpack(">d", _read_except(fp, 8))[0] + raise Exception("logic error, not float: 0x{:02x}".format(ord(code))) + + +def _unpack_string(code, fp, options): + if (ord(code) & 0xE0) == 0xA0: + length = ord(code) & ~0xE0 + elif code == b"\xd9": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xda": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdb": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not string: 0x{:02x}".format(ord(code))) + + data = _read_except(fp, length) + try: + return bytes.decode(data, "utf-8") + except Exception: + if options.get("allow_invalid_utf8", True): + return InvalidString(data) + raise InvalidStringException("unpacked string is invalid utf-8") + + +def _unpack_binary(code, fp, options): + if code == b"\xc4": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xc5": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xc6": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not binary: 0x{:02x}".format(ord(code))) + + return _read_except(fp, length) + + +def _unpack_ext(code, fp, options): + if code == b"\xd4": + length = 1 + elif code == b"\xd5": + length = 2 + elif code == b"\xd6": + length = 4 + elif code == b"\xd7": + length = 8 + elif code == b"\xd8": + length = 16 + elif code == b"\xc7": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xc8": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xc9": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not ext: 0x{:02x}".format(ord(code))) + + ext_type = struct.unpack("b", _read_except(fp, 1))[0] + ext_data = _read_except(fp, length) + + # Unpack with ext handler, if we have one + ext_handlers = options.get("ext_handlers") + if ext_handlers and ext_type in ext_handlers: + return ext_handlers[ext_type](Ext(ext_type, ext_data)) + + # Unpack with ext classes, if type is registered + if ext_type in _ext_type_to_class: + try: + return _ext_type_to_class[ext_type].unpackb(ext_data) + except AttributeError: + raise NotImplementedError( + "Ext serializable class {:s} is missing implementation of unpackb()".format(repr(_ext_type_to_class[ext_type])) + ) + + return Ext(ext_type, ext_data) + + +def _unpack_array(code, fp, options): + if (ord(code) & 0xF0) == 0x90: + length = ord(code) & ~0xF0 + elif code == b"\xdc": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdd": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not array: 0x{:02x}".format(ord(code))) + + if options.get("use_tuple"): + return tuple((_unpack(fp, options) for i in range(length))) + + return [_unpack(fp, options) for i in range(length)] + + +def _deep_list_to_tuple(obj): + if isinstance(obj, list): + return tuple([_deep_list_to_tuple(e) for e in obj]) + return obj + + +def _unpack_map(code, fp, options): + if (ord(code) & 0xF0) == 0x80: + length = ord(code) & ~0xF0 + elif code == b"\xde": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdf": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not map: 0x{:02x}".format(ord(code))) + + d = {} if not options.get("use_ordered_dict") else collections.OrderedDict() + for _ in range(length): + # Unpack key + k = _unpack(fp, options) + + if isinstance(k, list): + # Attempt to convert list into a hashable tuple + k = _deep_list_to_tuple(k) + try: + hash(k) + except Exception: + raise UnhashableKeyException('encountered unhashable key: "{:s}" ({:s})'.format(str(k), str(type(k)))) + if k in d: + raise DuplicateKeyException('encountered duplicate key: "{:s}" ({:s})'.format(str(k), str(type(k)))) + + # Unpack value + v = _unpack(fp, options) + + try: + d[k] = v + except TypeError: + raise UnhashableKeyException('encountered unhashable key: "{:s}"'.format(str(k))) + return d + + +def _unpack(fp, options): + code = _read_except(fp, 1) + return _unpack_dispatch_table[code](code, fp, options) + + +def unpack(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {'compact': True, 'schema': 0} + """ + return _unpack(fp, options) + + +# For Python 3, expects a bytes object +def unpackb(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s (bytes, bytearray): serialized MessagePack bytes + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + TypeError: + Packed data type is neither 'bytes' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\\x82\\xa7compact\\xc3\\xa6schema\\x00') + {'compact': True, 'schema': 0} + """ + if not isinstance(s, (bytes, bytearray)): + raise TypeError("packed data must be type 'bytes' or 'bytearray'") + return _unpack(io.BytesIO(s), options) + + +############################################################################# +# Module Initialization +############################################################################# + + +def __init(): + global _unpack_dispatch_table + # Build a dispatch table for fast lookup of unpacking function + _unpack_dispatch_table = {} + # Fix uint + for code in range(0, 0x7F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fix map + for code in range(0x80, 0x8F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_map + # Fix array + for code in range(0x90, 0x9F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_array + # Fix str + for code in range(0xA0, 0xBF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Nil + _unpack_dispatch_table[b"\xc0"] = _unpack_nil + # Reserved + _unpack_dispatch_table[b"\xc1"] = _unpack_reserved + # Boolean + _unpack_dispatch_table[b"\xc2"] = _unpack_boolean + _unpack_dispatch_table[b"\xc3"] = _unpack_boolean + # Bin + for code in range(0xC4, 0xC6 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_binary + # Ext + for code in range(0xC7, 0xC9 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # Float + _unpack_dispatch_table[b"\xca"] = _unpack_float + _unpack_dispatch_table[b"\xcb"] = _unpack_float + # Uint + for code in range(0xCC, 0xCF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Int + for code in range(0xD0, 0xD3 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fixext + for code in range(0xD4, 0xD8 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # String + for code in range(0xD9, 0xDB + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Array + _unpack_dispatch_table[b"\xdc"] = _unpack_array + _unpack_dispatch_table[b"\xdd"] = _unpack_array + # Map + _unpack_dispatch_table[b"\xde"] = _unpack_map + _unpack_dispatch_table[b"\xdf"] = _unpack_map + # Negative fixint + for code in range(0xE0, 0xFF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + + +__init() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpack.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpack.pyi new file mode 100644 index 000000000..2dec10602 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpack.pyi @@ -0,0 +1,278 @@ +from _typeshed import Incomplete + +__version__: str +version: Incomplete + +class Ext: + """ + The Ext class facilitates creating a serializable extension object to store + an application-defined type and data byte array. + """ + + type: Incomplete + data: Incomplete + def __init__(self, type, data) -> None: + """ + Construct a new Ext object. + + Args: + type (int): application-defined type integer + data (bytes): application-defined data byte array + + Raises: + TypeError: + Type is not an integer. + ValueError: + Type is out of range of -128 to 127. + TypeError: + Data is not type \'bytes\' (Python 3) or not type \'str\' (Python 2). + + Example: + >>> foo = umsgpack.Ext(5, b"\\x01\\x02\\x03") + >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) + \'\\x82\\xa7awesome\\xc3\\xadspecial stuff\\xc7\\x03\\x05\\x01\\x02\\x03\' + >>> bar = umsgpack.unpackb(_) + >>> print(bar["special stuff"]) + Ext Object (Type: 5, Data: 01 02 03) + """ + def __eq__(self, other): + """ + Compare this Ext object with another for equality. + """ + def __ne__(self, other): + """ + Compare this Ext object with another for inequality. + """ + def __str__(self) -> str: + """ + String representation of this Ext object. + """ + def __hash__(self): + """ + Provide a hash of this Ext object. + """ + +class InvalidString(bytes): + """Subclass of bytes to hold invalid UTF-8 strings.""" + +_ext_class_to_type: Incomplete +_ext_type_to_class: Incomplete + +def ext_serializable(ext_type): + """ + Return a decorator to register a class for automatic packing and unpacking + with the specified Ext type code. The application class should implement a + `packb()` method that returns serialized bytes, and an `unpackb()` class + method or static method that accepts serialized bytes and returns an + instance of the application class. + + Args: + ext_type (int): application-defined Ext type code + + Raises: + TypeError: + Ext type is not an integer. + ValueError: + Ext type is out of range of -128 to 127. + ValueError: + Ext type or class already registered. + """ + +class PackException(Exception): + """Base class for exceptions encountered during packing.""" + +class UnpackException(Exception): + """Base class for exceptions encountered during unpacking.""" + +class UnsupportedTypeException(PackException): + """Object type not supported for packing.""" + +class InsufficientDataException(UnpackException): + """Insufficient data to unpack the serialized object.""" + +class InvalidStringException(UnpackException): + """Invalid UTF-8 string encountered during unpacking.""" + +class UnsupportedTimestampException(UnpackException): + """Unsupported timestamp format encountered during unpacking.""" + +class ReservedCodeException(UnpackException): + """Reserved code encountered during unpacking.""" + +class UnhashableKeyException(UnpackException): + """ + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + """ + +class DuplicateKeyException(UnpackException): + """Duplicate key encountered during map unpacking.""" + +def _pack_integer(obj, fp, options) -> None: ... +def _pack_nil(obj, fp, options) -> None: ... +def _pack_boolean(obj, fp, options) -> None: ... +def _pack_float(obj, fp, options) -> None: ... +def _pack_string(obj, fp, options) -> None: ... +def _pack_binary(obj, fp, options) -> None: ... +def _pack_oldspec_raw(obj, fp, options) -> None: ... +def _pack_ext(obj, fp, options) -> None: ... +def _pack_array(obj, fp, options) -> None: ... +def _pack_map(obj, fp, options) -> None: ... +def pack(obj, fp, **options) -> None: + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + None + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> f = open(\'test.bin\', \'wb\') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + """ + +def packb(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + bytes: Serialized MessagePack bytes + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + b\'\\x82\\xa7compact\\xc3\\xa6schema\\x00\' + """ + +def _read_except(fp, n): ... +def _unpack_integer(code, fp, options): ... +def _unpack_reserved(code, fp, options) -> None: ... +def _unpack_nil(code, fp, options) -> None: ... +def _unpack_boolean(code, fp, options): ... +def _unpack_float(code, fp, options): ... +def _unpack_string(code, fp, options): ... +def _unpack_binary(code, fp, options): ... +def _unpack_ext(code, fp, options): ... +def _unpack_array(code, fp, options): ... +def _deep_list_to_tuple(obj): ... +def _unpack_map(code, fp, options): ... +def _unpack(fp, options): ... +def unpack(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {'compact': True, 'schema': 0} + """ + +def unpackb(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s (bytes, bytearray): serialized MessagePack bytes + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + TypeError: + Packed data type is neither 'bytes' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\\x82\\xa7compact\\xc3\\xa6schema\\x00') + {'compact': True, 'schema': 0} + """ + +def __init() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpackrpc.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpackrpc.py new file mode 100644 index 000000000..e65c32e83 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpackrpc.py @@ -0,0 +1,202 @@ +# This file is part of the msgpack-rpc module. +# Copyright (c) 2023 Arduino SA +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# MessagePack RPC protocol implementation for MicroPython. +# https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md + +import logging +import openamp +import msgpack +from micropython import const +from io import BytesIO +from time import sleep_ms, ticks_ms, ticks_diff + +_MSG_TYPE_REQUEST = 0 +_MSG_TYPE_RESPONSE = 1 +_MSG_TYPE_NOTIFY = 2 + + +def log_level_enabled(level): + return logging.getLogger().isEnabledFor(level) + + +class Future: + def __init__(self, msgid, msgbuf, fname, fargs): + self.msgid = msgid + self.msgbuf = msgbuf + self.fname = fname + self.fargs = fargs + + def join(self, timeout=0): + if log_level_enabled(logging.DEBUG): + logging.debug(f"join {self.fname}()") + + if timeout > 0: + t = ticks_ms() + + while self.msgid not in self.msgbuf: + if timeout > 0 and ticks_diff(ticks_ms(), t) > timeout: + raise OSError(f"Timeout joining function {self.fname}") + sleep_ms(100) + + obj = self.msgbuf.pop(self.msgid) + if obj[2] is not None: + raise (OSError(obj[2])) + + if log_level_enabled(logging.DEBUG): + logging.debug(f"call {self.fname}({self.fargs}) => {obj}") + return obj[3] + + +class MsgPackIO: + def __init__(self): + self.stream = BytesIO() + + def feed(self, data): + offset = self.stream.tell() + self.stream.write(data) + self.stream.seek(offset) + + def readable(self): + if self.stream.read(1): + offset = self.stream.tell() + self.stream.seek(offset - 1) + return True + return False + + def truncate(self): + if self.readable(): + offset = self.stream.tell() + self.stream = BytesIO(self.stream.getvalue()[offset:]) + + def __iter__(self): + return self + + def __next__(self): + offset = self.stream.tell() + try: + obj = msgpack.unpack(self.stream) + self.truncate() + return obj + except Exception: + self.stream.seek(offset) + raise StopIteration + + +class MsgPackRPC: + def __init__(self, streaming=False): + """ + Create a MsgPack RPC object. + streaming: If True, messages can span multiple buffers, otherwise a buffer contains + exactly one full message. Note streaming mode is slower, so it should be disabled + if it's not needed. + """ + self.epts = {} + self.msgid = 0 + self.msgbuf = {} + self.msgio = MsgPackIO() if streaming else None + self.callables = {} + + def _bind_callback(self, src, name): + if log_level_enabled(logging.INFO): + logging.info(f'New service announcement src: {src} name: "{name}"') + self.epts[name] = openamp.Endpoint(name, self._recv_callback, dest=src) + self.epts[name].send(b"\x00") + + def _recv_callback(self, src, data): + if log_level_enabled(logging.DEBUG): + logging.debug(f"Received message on endpoint: {src} data: {bytes(data)}") + + if self.msgio is None: + obj = msgpack.unpackb(data) + self._process_unpacked_obj(obj) + else: + self.msgio.feed(data) + for obj in self.msgio: + self._process_unpacked_obj(obj) + + def _process_unpacked_obj(self, obj): + if obj[0] == _MSG_TYPE_RESPONSE: + self.msgbuf[obj[1]] = obj + elif obj[0] == _MSG_TYPE_REQUEST: + self._dispatch(obj[1], obj[2], obj[-1]) + if log_level_enabled(logging.DEBUG): + logging.debug(f"Unpacked {type(obj)} val: {obj}") + + def _send_msg(self, msgid, msgtype, fname, fargs, **kwargs): + timeout = kwargs.pop("timeout", 1000) + endpoint = kwargs.pop("endpoint", "rpc") + self.epts[endpoint].send(msgpack.packb([msgtype, msgid, fname, fargs]), timeout=timeout) + if msgtype == _MSG_TYPE_REQUEST: + self.msgid += 1 + return Future(msgid, self.msgbuf, fname, fargs) + + def _dispatch(self, msgid, fname, fargs): + retobj = None + error = None + + if fname in self.callables: + retobj = self.callables[fname](*fargs) + else: + error = "Unbound function called %s" % (fname) + + self._send_msg(msgid, _MSG_TYPE_RESPONSE, error, retobj) + + def bind(self, name, obj): + """ + Bind a callable or an object to a name. + name: The name to which the callable or object is bound. + obj: A callable or an object to bind to the name. If an object is passed, all of its + public methods will be bound to their respective qualified names. + """ + if callable(obj): + # Bind a single callable to its name. + self.callables[name] = obj + else: + # Bind all public methods of an object to their respective qualified names. + for k, v in obj.__class__.__dict__.items(): + if callable(v) and not k.startswith("_"): + self.callables[name + "." + k] = getattr(obj, k) + + def start(self, firmware=None, num_channels=2, timeout=3000): + """ + Initializes OpenAMP, loads the remote processor's firmware and starts. + firmware: A path to an elf file stored in the filesystem, or an address to an entry point in flash. + num_channels: The number of channels to wait for the remote processor to + create before starting to communicate with it. + timeout: How long to wait for the remote processor to start, 0 means forever. + """ + # Initialize OpenAMP and set the New Service callback. + openamp.new_service_callback(self._bind_callback) + + # Keep a reference to the remote processor object, to stop the GC from collecting + # it, which would call the finaliser and shut down the remote processor while it's + # still being used. + self.rproc = openamp.RemoteProc(firmware) + self.rproc.start() + + # Wait for remote processor to announce the end points. + t = ticks_ms() + while len(self.epts) != num_channels: + if timeout > 0 and ticks_diff(ticks_ms(), t) > timeout: + raise OSError("timeout waiting for the remote processor to start") + sleep_ms(10) + + # Introduce a brief delay to allow the M4 sufficient time + # to bind remote functions before invoking them. + sleep_ms(100) + + def call(self, fname, *args, **kwargs): + """ + Synchronous call. The client is blocked until the RPC is finished. + """ + return self.call_async(fname, *args, *kwargs).join() + + def call_async(self, fname, *args, **kwargs): + """ + Asynchronous call. The client returns a Future object immediately. + """ + return self._send_msg(self.msgid, _MSG_TYPE_REQUEST, fname, list(args), *kwargs) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpackrpc.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpackrpc.pyi new file mode 100644 index 000000000..25c365b6d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/msgpackrpc.pyi @@ -0,0 +1,68 @@ +from _typeshed import Incomplete +from micropython import const as const + +_MSG_TYPE_REQUEST: int +_MSG_TYPE_RESPONSE: int +_MSG_TYPE_NOTIFY: int + +def log_level_enabled(level): ... + +class Future: + msgid: Incomplete + msgbuf: Incomplete + fname: Incomplete + fargs: Incomplete + def __init__(self, msgid, msgbuf, fname, fargs) -> None: ... + def join(self, timeout: int = 0): ... + +class MsgPackIO: + stream: Incomplete + def __init__(self) -> None: ... + def feed(self, data) -> None: ... + def readable(self): ... + def truncate(self) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class MsgPackRPC: + epts: Incomplete + msgid: int + msgbuf: Incomplete + msgio: Incomplete + callables: Incomplete + def __init__(self, streaming: bool = False) -> None: + """ + Create a MsgPack RPC object. + streaming: If True, messages can span multiple buffers, otherwise a buffer contains + exactly one full message. Note streaming mode is slower, so it should be disabled + if it's not needed. + """ + def _bind_callback(self, src, name) -> None: ... + def _recv_callback(self, src, data) -> None: ... + def _process_unpacked_obj(self, obj) -> None: ... + def _send_msg(self, msgid, msgtype, fname, fargs, **kwargs): ... + def _dispatch(self, msgid, fname, fargs) -> None: ... + def bind(self, name, obj) -> None: + """ + Bind a callable or an object to a name. + name: The name to which the callable or object is bound. + obj: A callable or an object to bind to the name. If an object is passed, all of its + public methods will be bound to their respective qualified names. + """ + rproc: Incomplete + def start(self, firmware=None, num_channels: int = 2, timeout: int = 3000) -> None: + """ + Initializes OpenAMP, loads the remote processor's firmware and starts. + firmware: A path to an elf file stored in the filesystem, or an address to an entry point in flash. + num_channels: The number of channels to wait for the remote processor to + create before starting to communicate with it. + timeout: How long to wait for the remote processor to start, 0 means forever. + """ + def call(self, fname, *args, **kwargs): + """ + Synchronous call. The client is blocked until the RPC is finished. + """ + def call_async(self, fname, *args, **kwargs): + """ + Asynchronous call. The client returns a Future object immediately. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/__init__.py new file mode 100644 index 000000000..908375fdb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/__init__.py @@ -0,0 +1,29 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from .senml_base import SenmlBase +from .senml_pack import SenmlPack +from .senml_record import SenmlRecord +from .senml_unit import SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/__init__.pyi new file mode 100644 index 000000000..c72285dc4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/__init__.pyi @@ -0,0 +1,4 @@ +from .senml_base import SenmlBase as SenmlBase +from .senml_pack import SenmlPack as SenmlPack +from .senml_record import SenmlRecord as SenmlRecord +from .senml_unit import SenmlUnits as SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_base.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_base.py new file mode 100644 index 000000000..b277c9477 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_base.py @@ -0,0 +1,30 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +class SenmlBase(object): + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_base.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_base.pyi new file mode 100644 index 000000000..240f185ce --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_base.pyi @@ -0,0 +1,4 @@ +class SenmlBase: + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_pack.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_pack.py new file mode 100644 index 000000000..5a0554467 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_pack.py @@ -0,0 +1,358 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from senml.senml_record import SenmlRecord +from senml.senml_base import SenmlBase +import json +import cbor2 + + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + def __init__(self, list): + self._list = list + self._index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self._index < len(self._list): + res = self._list[self._index] + self._index += 1 + return res + else: + raise StopIteration + + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings = { + "bn": "bn", + "bt": "bt", + "bu": "bu", + "bv": "bv", + "bs": "bs", + "n": "n", + "u": "u", + "v": "v", + "vs": "vs", + "vb": "vb", + "vd": "vd", + "s": "s", + "t": "t", + "ut": "ut", + } + + def __init__(self, name, callback=None): + """ + initialize the object + :param name: {string} the name of the pack + """ + self._data = [] + self.name = name + self._base_value = None + self._base_time = None + self._base_sum = None + self.base_unit = None + self._parent = None # a pack can also be the child of another pack. + self.actuate = callback # actuate callback function + + def __iter__(self): + return SenmlPackIterator(self._data) + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + return self._base_value + + @base_value.setter + def base_value(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_value") + self._base_value = value + + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + return self._base_sum + + @base_sum.setter + def base_sum(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_sum") + self._base_sum = value + + @property + def base_time(self): + return self._base_time + + @base_time.setter + def base_time(self, value): + self._check_value_type(value, "base_time") + self._base_time = value + + def _check_value_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + def from_json(self, data): + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + records = json.loads(data) # load the raw senml data + self._process_incomming_data(records, SenmlPack.json_mappings) + + def _process_incomming_data(self, records, naming_map): + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + cur_pack_el = self + new_pack = False + for item in records: + if naming_map["bn"] in item: # ref to a pack element, either this or a child pack. + if item[naming_map["bn"]] != self.name: + pack_el = [x for x in self._data if x.name == item[naming_map["bn"]]] + else: + pack_el = [self] + if len(pack_el) > 0: + cur_pack_el = pack_el[0] + new_pack = False + else: + device = SenmlPack(item[naming_map["bn"]]) + self._data.append(device) + cur_pack_el = device + new_pack = True + + if ( + naming_map["bv"] in item + ): # need to copy the base value assigned to the pack element so we can do proper conversion for actuators. + cur_pack_el.base_value = item[naming_map["bv"]] + + rec_el = [x for x in cur_pack_el._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + else: + rec_el = [x for x in self._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + + def do_actuate(self, raw, naming_map, device=None): + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + rec = SenmlRecord(raw[naming_map["n"]]) + if device: + device.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=device) + else: + self.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=None) + + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + converted = [] + self._build_rec_dict(SenmlPack.json_mappings, converted) + return json.dumps(converted) + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + internalList = [] + for item in self._data: + item._build_rec_dict(naming_map, internalList) + if len(internalList) > 0: + first_rec = internalList[0] + else: + first_rec = {} + internalList.append(first_rec) + + if self.name: + first_rec[naming_map["bn"]] = self.name + if self.base_value: + first_rec[naming_map["bv"]] = self.base_value + if self.base_unit: + first_rec[naming_map["bu"]] = self.base_unit + if self.base_sum: + first_rec[naming_map["bs"]] = self.base_sum + if self.base_time: + first_rec[naming_map["bt"]] = self.base_time + appendTo.extend(internalList) + + def from_cbor(self, data): + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + records = cbor2.loads(data) # load the raw senml data + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + self._process_incomming_data(records, naming_map) + + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + converted = [] + self._build_rec_dict(naming_map, converted) + return cbor2.dumps(converted) + + def add(self, item): + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if item._parent is not None: + raise Exception("item is already part of a pack") + + self._data.append(item) + item._parent = self + + def remove(self, item): + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if not item._parent == self: + raise Exception("item is not part of this pack") + + self._data.remove(item) + item._parent = None + + def clear(self): + """ + clear the list of the pack + :return: None + """ + for item in self._data: + item._parent = None + self._data = [] diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_pack.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_pack.pyi new file mode 100644 index 000000000..57a0cf547 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_pack.pyi @@ -0,0 +1,143 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase +from senml.senml_record import SenmlRecord as SenmlRecord + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + _list: Incomplete + _index: int + def __init__(self, list) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings: Incomplete + _data: Incomplete + name: Incomplete + _base_value: Incomplete + _base_time: Incomplete + _base_sum: Incomplete + base_unit: Incomplete + _parent: Incomplete + actuate: Incomplete + def __init__(self, name, callback=None) -> None: + """ + initialize the object + :param name: {string} the name of the pack + """ + def __iter__(self): ... + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + @base_value.setter + def base_value(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + @base_sum.setter + def base_sum(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_time(self): ... + @base_time.setter + def base_time(self, value) -> None: ... + def _check_value_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def from_json(self, data) -> None: + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + def _process_incomming_data(self, records, naming_map) -> None: + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + def do_actuate(self, raw, naming_map, device=None) -> None: + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + def from_cbor(self, data) -> None: + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + def add(self, item) -> None: + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + def remove(self, item) -> None: + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + def clear(self) -> None: + """ + clear the list of the pack + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_record.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_record.py new file mode 100644 index 000000000..b5b07b0bc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_record.py @@ -0,0 +1,240 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import binascii +from senml.senml_base import SenmlBase + + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + def __init__(self, name, **kwargs): + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + self.__parent = None # using double __ cause it's a field for an internal property + self._unit = None # declare and init internal fields + self._value = None + self._time = None + self._sum = None + self._update_time = None + + self._parent = None # internal reference to the parent object + self.name = name + self.unit = kwargs.get("unit", None) + self.value = kwargs.get("value", None) + self.time = kwargs.get("time", None) + self.sum = kwargs.get("sum", None) + self.update_time = kwargs.get("update_time", None) + self.actuate = kwargs.get("callback", None) # actuate callback function + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + def _check_value_type(self, value): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not ( + isinstance(value, bool) + or isinstance(value, int) + or isinstance(value, float) + or isinstance(value, bytearray) + or isinstance(value, str) + ): + raise Exception("invalid type for value, only numbers, strings, boolean and byte arrays allowed") + + def _check_number_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + @property + def value(self): + """get the value currently assigned to the object""" + return self._value + + @value.setter + def value(self, value): + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + self._check_value_type(value) + self._value = value + + @property + def time(self): + return self._time + + @time.setter + def time(self, value): + self._check_number_type(value, "time") + self._time = value + + @property + def update_time(self): + return self._update_time + + @update_time.setter + def update_time(self, value): + self._check_number_type(value, "update_time") + self._update_time = value + + @property + def sum(self): + return self._sum + + @sum.setter + def sum(self, value): + self._check_number_type(value, "sum") + self._sum = value + + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + return self.__parent + + @_parent.setter + def _parent(self, value): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + self.__parent = value + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + result = {} + + if self.name: + result[naming_map["n"]] = self.name + + if self._sum: + if self._parent and self._parent.base_sum: + result[naming_map["s"]] = self._sum - self._parent.base_sum + else: + result[naming_map["s"]] = self._sum + elif isinstance(self._value, bool): + result[naming_map["vb"]] = self._value + elif isinstance(self._value, int) or isinstance(self._value, float): + if self._parent and self._parent.base_value: + result[naming_map["v"]] = self._value - self._parent.base_value + else: + result[naming_map["v"]] = self._value + elif isinstance(self._value, str): + result[naming_map["vs"]] = self._value + elif isinstance(self._value, bytearray): + if naming_map["vd"] == "vd": # neeed to make a distinction between json (needs base64) and cbor (needs binary) + result[naming_map["vd"]] = binascii.b2a_base64(self._value, newline=False).decode("utf8") + else: + result[naming_map["vd"]] = self._value + else: + raise Exception("sum or value of type bootl, number, string or byte-array is required") + + if self._time: + if self._parent and self._parent.base_time: + result[naming_map["t"]] = self._time - self._parent.base_time + else: + result[naming_map["t"]] = self._time + + if self.unit: + result[naming_map["u"]] = self.unit + + if self._update_time: + if self._parent and self._parent.base_time: + result[naming_map["ut"]] = self._update_time - self._parent.base_time + else: + result[naming_map["ut"]] = self._update_time + + appendTo.append(result) + + def _from_raw(self, raw, naming_map): + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + if naming_map["v"] in raw: + val = raw[naming_map["v"]] + if self._parent and self._parent.base_value: + val += self._parent.base_value + elif naming_map["vs"] in raw: + val = raw[naming_map["vs"]] + elif naming_map["vb"] in raw: + val = raw[naming_map["vb"]] + elif naming_map["vd"] in raw: + val = binascii.a2b_base64(raw[naming_map["vb"]]) + else: + val = None + self.value = val + + def do_actuate(self, raw, naming_map): + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ + self._from_raw(raw, naming_map) + if self.actuate: + self.actuate(self) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_record.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_record.pyi new file mode 100644 index 000000000..61c0c7c05 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_record.pyi @@ -0,0 +1,104 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + __parent: Incomplete + _unit: Incomplete + _value: Incomplete + _time: Incomplete + _sum: Incomplete + _update_time: Incomplete + name: Incomplete + unit: Incomplete + actuate: Incomplete + def __init__(self, name, **kwargs) -> None: + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + def _check_value_type(self, value) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def _check_number_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + @property + def value(self): + """get the value currently assigned to the object""" + @value.setter + def value(self, value) -> None: + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + @property + def time(self): ... + @time.setter + def time(self, value) -> None: ... + @property + def update_time(self): ... + @update_time.setter + def update_time(self, value) -> None: ... + @property + def sum(self): ... + @sum.setter + def sum(self, value) -> None: ... + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + @_parent.setter + def _parent(self, value) -> None: + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + def _from_raw(self, raw, naming_map) -> None: + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + def do_actuate(self, raw, naming_map) -> None: + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_unit.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_unit.py new file mode 100644 index 000000000..bf7753c4d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_unit.py @@ -0,0 +1,89 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +def enum(**enums): + return type("Enum", (), enums) + + +SenmlUnits = enum( + SENML_UNIT_METER="m", + SENML_UNIT_KILOGRAM="kg", + SENML_UNIT_GRAM="g", + SENML_UNIT_SECOND="s", + SENML_UNIT_AMPERE="A", + SENML_UNIT_KELVIN="K", + SENML_UNIT_CANDELA="cd", + SENML_UNIT_MOLE="mol", + SENML_UNIT_HERTZ="Hz", + SENML_UNIT_RADIAN="rad", + SENML_UNIT_STERADIAN="sr", + SENML_UNIT_NEWTON="N", + SENML_UNIT_PASCAL="Pa", + SENML_UNIT_JOULE="J", + SENML_UNIT_WATT="W", + SENML_UNIT_COULOMB="C", + SENML_UNIT_VOLT="V", + SENML_UNIT_FARAD="F", + SENML_UNIT_OHM="Ohm", + SENML_UNIT_SIEMENS="S", + SENML_UNIT_WEBER="Wb", + SENML_UNIT_TESLA="T", + SENML_UNIT_HENRY="H", + SENML_UNIT_DEGREES_CELSIUS="Cel", + SENML_UNIT_LUMEN="lm", + SENML_UNIT_LUX="lx", + SENML_UNIT_BECQUEREL="Bq", + SENML_UNIT_GRAY="Gy", + SENML_UNIT_SIEVERT="Sv", + SENML_UNIT_KATAL="kat", + SENML_UNIT_SQUARE_METER="m2", + SENML_UNIT_CUBIC_METER="m3", + SENML_UNIT_LITER="l", + SENML_UNIT_VELOCITY="m/s", + SENML_UNIT_ACCELERATION="m/s2", + SENML_UNIT_CUBIC_METER_PER_SECOND="m3/s", + SENML_UNIT_LITER_PER_SECOND="l/s", + SENML_UNIT_WATT_PER_SQUARE_METER="W/m2", + SENML_UNIT_CANDELA_PER_SQUARE_METER="cd/m2", + SENML_UNIT_BIT="bit", + SENML_UNIT_BIT_PER_SECOND="bit/s", + SENML_UNIT_DEGREES_LATITUDE="lat", + SENML_UNIT_DEGREES_LONGITUDE="lon", + SENML_UNIT_PH="pH", + SENML_UNIT_DECIBEL="db", + SENML_UNIT_DECIBEL_RELATIVE_TO_1_W="dBW", + SENML_UNIT_BEL="Bspl", + SENML_UNIT_COUNTER="count", + SENML_UNIT_RATIO="//", + SENML_UNIT_RELATIVE_HUMIDITY="%RH", + SENML_UNIT_PERCENTAGE_REMAINING_BATTERY_LEVEL="%EL", + SENML_UNIT_SECONDS_REMAINING_BATTERY_LEVEL="EL", + SENML_UNIT_EVENT_RATE_PER_SECOND="1/s", + SENML_UNIT_EVENT_RATE_PER_MINUTE="1/min", + SENML_UNIT_BPM="beat/min", + SENML_UNIT_BEATS="beats", + SENML_UNIT_SIEMENS_PER_METER="S/m", +) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_unit.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_unit.pyi new file mode 100644 index 000000000..6b3e7ae68 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/senml/senml_unit.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +def enum(**enums): ... + +SenmlUnits: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/time.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/time.py new file mode 100644 index 000000000..f79ab8a3b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/time.py @@ -0,0 +1,79 @@ +from utime import * +from micropython import const + +_TS_YEAR = 0 +_TS_MON = 1 +_TS_MDAY = 2 +_TS_HOUR = 3 +_TS_MIN = 4 +_TS_SEC = 5 +_TS_WDAY = 6 +_TS_YDAY = 7 +_TS_ISDST = 8 + +_WDAY = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") +_MDAY = const( + ( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ) +) + + +def strftime(datefmt, ts): + from io import StringIO + + fmtsp = False + ftime = StringIO() + for k in datefmt: + if fmtsp: + if k == "a": + ftime.write(_WDAY[ts[_TS_WDAY]][0:3]) + elif k == "A": + ftime.write(_WDAY[ts[_TS_WDAY]]) + elif k == "b": + ftime.write(_MDAY[ts[_TS_MON] - 1][0:3]) + elif k == "B": + ftime.write(_MDAY[ts[_TS_MON] - 1]) + elif k == "d": + ftime.write("%02d" % ts[_TS_MDAY]) + elif k == "H": + ftime.write("%02d" % ts[_TS_HOUR]) + elif k == "I": + ftime.write("%02d" % (ts[_TS_HOUR] % 12)) + elif k == "j": + ftime.write("%03d" % ts[_TS_YDAY]) + elif k == "m": + ftime.write("%02d" % ts[_TS_MON]) + elif k == "M": + ftime.write("%02d" % ts[_TS_MIN]) + elif k == "P": + ftime.write("AM" if ts[_TS_HOUR] < 12 else "PM") + elif k == "S": + ftime.write("%02d" % ts[_TS_SEC]) + elif k == "w": + ftime.write(str(ts[_TS_WDAY])) + elif k == "y": + ftime.write("%02d" % (ts[_TS_YEAR] % 100)) + elif k == "Y": + ftime.write(str(ts[_TS_YEAR])) + else: + ftime.write(k) + fmtsp = False + elif k == "%": + fmtsp = True + else: + ftime.write(k) + val = ftime.getvalue() + ftime.close() + return val diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/time.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/time.pyi new file mode 100644 index 000000000..26b0e4b08 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/time.pyi @@ -0,0 +1,59 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. +""" + +from __future__ import annotations +from utime import * +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TS_YEAR: int +_TS_MON: int +_TS_MDAY: int +_TS_HOUR: int +_TS_MIN: int +_TS_SEC: int +_TS_WDAY: int +_TS_YDAY: int +_TS_ISDST: int +_WDAY: Incomplete +_MDAY: Incomplete +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def strftime(datefmt, ts): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_GIGA/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/central.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/client.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/core.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/device.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/security.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/server.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/__init__.py new file mode 100644 index 000000000..80790f0da --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/__init__.py @@ -0,0 +1,32 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from ._decoder import CBORDecoder +from ._decoder import load +from ._decoder import loads + +from ._encoder import CBOREncoder +from ._encoder import dump +from ._encoder import dumps diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/__init__.pyi new file mode 100644 index 000000000..0ef59d019 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/__init__.pyi @@ -0,0 +1,2 @@ +from ._decoder import CBORDecoder as CBORDecoder, load as load, loads as loads +from ._encoder import CBOREncoder as CBOREncoder, dump as dump, dumps as dumps diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_decoder.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_decoder.py new file mode 100644 index 000000000..8434aec26 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_decoder.py @@ -0,0 +1,254 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + + +break_marker = object() + + +class CBORSimpleValue(object): + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + def __init__(self, value): + if value < 0 or value > 255: + raise TypeError("simple value too big") + self.value = value + + def __eq__(self, other): + if isinstance(other, CBORSimpleValue): + return self.value == other.value + elif isinstance(other, int): + return self.value == other + return NotImplemented + + def __repr__(self): + return "CBORSimpleValue({self.value})".format(self=self) + + +def decode_uint(decoder, subtype, allow_indefinite=False): + # Major tag 0 + if subtype < 24: + return subtype + elif subtype == 24: + return struct.unpack(">B", decoder.read(1))[0] + elif subtype == 25: + return struct.unpack(">H", decoder.read(2))[0] + elif subtype == 26: + return struct.unpack(">L", decoder.read(4))[0] + elif subtype == 27: + return struct.unpack(">Q", decoder.read(8))[0] + elif subtype == 31 and allow_indefinite: + return None + else: + raise CBORDecodeError("unknown unsigned integer subtype 0x%x" % subtype) + + +def decode_negint(decoder, subtype): + # Major tag 1 + uint = decode_uint(decoder, subtype) + return -uint - 1 + + +def decode_bytestring(decoder, subtype): + # Major tag 2 + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + buf = bytearray() + while True: + initial_byte = decoder.read(1)[0] + if initial_byte == 255: + return buf + else: + length = decode_uint(decoder, initial_byte & 31) + value = decoder.read(length) + buf.extend(value) + else: + return decoder.read(length) + + +def decode_string(decoder, subtype): + # Major tag 3 + return decode_bytestring(decoder, subtype).decode("utf-8") + + +def decode_array(decoder, subtype): + # Major tag 4 + items = [] + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + value = decoder.decode() + if value is break_marker: + break + else: + items.append(value) + else: + for _ in range(length): + item = decoder.decode() + items.append(item) + return items + + +def decode_map(decoder, subtype): + # Major tag 5 + dictionary = {} + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + key = decoder.decode() + if key is break_marker: + break + else: + value = decoder.decode() + dictionary[key] = value + else: + for _ in range(length): + key = decoder.decode() + value = decoder.decode() + dictionary[key] = value + + return dictionary + + +def decode_special(decoder, subtype): + # Simple value + if subtype < 20: + return CBORSimpleValue(subtype) + + # Major tag 7 + return special_decoders[subtype](decoder) + + +def decode_simple_value(decoder): + return CBORSimpleValue(struct.unpack(">B", decoder.read(1))[0]) + + +def decode_float16(decoder): + decoder.read(2) + raise NotImplementedError # no float16 unpack function + + +def decode_float32(decoder): + return struct.unpack(">f", decoder.read(4))[0] + + +def decode_float64(decoder): + return struct.unpack(">d", decoder.read(8))[0] + + +major_decoders = { + 0: decode_uint, + 1: decode_negint, + 2: decode_bytestring, + 3: decode_string, + 4: decode_array, + 5: decode_map, + 7: decode_special, +} + +special_decoders = { + 20: lambda self: False, + 21: lambda self: True, + 22: lambda self: None, + # 23 is undefined + 24: decode_simple_value, + 25: decode_float16, + 26: decode_float32, + 27: decode_float64, + 31: lambda self: break_marker, +} + + +class CBORDecoder(object): + """ + Deserializes a CBOR encoded byte stream. + """ + + def __init__(self, fp): + self.fp = fp + + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + data = self.fp.read(amount) + if len(data) < amount: + raise CBORDecodeError("premature end of stream (expected to read {} bytes, got {} instead)".format(amount, len(data))) + + return data + + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + try: + initial_byte = self.fp.read(1)[0] + major_type = initial_byte >> 5 + subtype = initial_byte & 31 + except Exception as e: + raise CBORDecodeError("error reading major type at index {}: {}".format(self.fp.tell(), e)) + + decoder = major_decoders[major_type] + try: + return decoder(self, subtype) + except CBORDecodeError: + raise + except Exception as e: + raise CBORDecodeError("error decoding value {}".format(e)) # tell doesn't work on micropython at the moment + + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + fp = io.BytesIO(payload) + return CBORDecoder(fp, **kwargs).decode() + + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + return CBORDecoder(fp, **kwargs).decode() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_decoder.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_decoder.pyi new file mode 100644 index 000000000..d4daffe85 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_decoder.pyi @@ -0,0 +1,66 @@ +from _typeshed import Incomplete + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + +break_marker: Incomplete + +class CBORSimpleValue: + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + value: Incomplete + def __init__(self, value) -> None: ... + def __eq__(self, other): ... + def __repr__(self) -> str: ... + +def decode_uint(decoder, subtype, allow_indefinite: bool = False): ... +def decode_negint(decoder, subtype): ... +def decode_bytestring(decoder, subtype): ... +def decode_string(decoder, subtype): ... +def decode_array(decoder, subtype): ... +def decode_map(decoder, subtype): ... +def decode_special(decoder, subtype): ... +def decode_simple_value(decoder): ... +def decode_float16(decoder) -> None: ... +def decode_float32(decoder): ... +def decode_float64(decoder): ... + +major_decoders: Incomplete +special_decoders: Incomplete + +class CBORDecoder: + """ + Deserializes a CBOR encoded byte stream. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_encoder.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_encoder.py new file mode 100644 index 000000000..fe8715468 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_encoder.py @@ -0,0 +1,182 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + + +def encode_length(major_tag, length): + if length < 24: + return struct.pack(">B", major_tag | length) + elif length < 256: + return struct.pack(">BB", major_tag | 24, length) + elif length < 65536: + return struct.pack(">BH", major_tag | 25, length) + elif length < 4294967296: + return struct.pack(">BL", major_tag | 26, length) + else: + return struct.pack(">BQ", major_tag | 27, length) + + +def encode_semantic(encoder, tag, value): + encoder.write(encode_length(0xC0, tag)) + encoder.encode(value) + + +def encode_float(encoder, value): + # Handle special values efficiently + import math + + if math.isnan(value): + encoder.write(b"\xf9\x7e\x00") + elif math.isinf(value): + encoder.write(b"\xf9\x7c\x00" if value > 0 else b"\xf9\xfc\x00") + else: + encoder.write(struct.pack(">Bd", 0xFB, value)) + + +def encode_int(encoder, value): + # Big integers (2 ** 64 and over) + if value >= 18446744073709551616 or value < -18446744073709551616: + if value >= 0: + major_type = 0x02 + else: + major_type = 0x03 + value = -value - 1 + + values = [] + while value > 0: + value, remainder = divmod(value, 256) + values.insert(0, remainder) + + payload = bytes(values) + encode_semantic(encoder, major_type, payload) + elif value >= 0: + encoder.write(encode_length(0, value)) + else: + encoder.write(encode_length(0x20, abs(value) - 1)) + + +def encode_bytestring(encoder, value): + encoder.write(encode_length(0x40, len(value)) + value) + + +def encode_bytearray(encoder, value): + encode_bytestring(encoder, bytes(value)) + + +def encode_string(encoder, value): + encoded = value.encode("utf-8") + encoder.write(encode_length(0x60, len(encoded)) + encoded) + + +def encode_map(encoder, value): + encoder.write(encode_length(0xA0, len(value))) + for key, val in value.items(): + encoder.encode(key) + encoder.encode(val) + + +def encode_array(encoder, value): + encoder.write(encode_length(0x80, len(value))) + for item in value: + encoder.encode(item) + + +def encode_boolean(encoder, value): + encoder.write(b"\xf5" if value else b"\xf4") + + +def encode_none(encoder, value): + encoder.write(b"\xf6") + + +cbor_encoders = { # supported data types and the encoder to use. + bytes: encode_bytestring, + bytearray: encode_bytearray, + str: encode_string, + int: encode_int, + float: encode_float, + bool: encode_boolean, + type(None): encode_none, + list: encode_array, + dict: encode_map, +} + + +class CBOREncoder(object): + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + def __init__(self, fp): + self.fp = fp + + def _find_encoder(self, obj): + return cbor_encoders[type(obj)] + + def write(self, data): + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + self.fp.write(data) + + def encode(self, obj): + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + encoder = self._find_encoder(obj) + if not encoder: + raise CBOREncodeError("cannot serialize type %s" % type(obj)) + encoder(self, obj) + + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + fp = io.BytesIO() + dump(obj, fp, **kwargs) + return fp.getvalue() + + +def dump(obj, fp, **kwargs): + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ + CBOREncoder(fp, **kwargs).encode(obj) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_encoder.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_encoder.pyi new file mode 100644 index 000000000..8cd761686 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/cbor2/_encoder.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + +def encode_length(major_tag, length): ... +def encode_semantic(encoder, tag, value) -> None: ... +def encode_float(encoder, value) -> None: ... +def encode_int(encoder, value) -> None: ... +def encode_bytestring(encoder, value) -> None: ... +def encode_bytearray(encoder, value) -> None: ... +def encode_string(encoder, value) -> None: ... +def encode_map(encoder, value) -> None: ... +def encode_array(encoder, value) -> None: ... +def encode_boolean(encoder, value) -> None: ... +def encode_none(encoder, value) -> None: ... + +cbor_encoders: Incomplete + +class CBOREncoder: + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def _find_encoder(self, obj): ... + def write(self, data) -> None: + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + def encode(self, obj) -> None: + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + +def dump(obj, fp, **kwargs) -> None: + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/logging.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/logging.py new file mode 100644 index 000000000..edee407c6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/logging.py @@ -0,0 +1,253 @@ +from micropython import const +import io +import sys +import time + +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 + +_DEFAULT_LEVEL = WARNING + +_level_dict = { + CRITICAL: "CRITICAL", + ERROR: "ERROR", + WARNING: "WARNING", + INFO: "INFO", + DEBUG: "DEBUG", + NOTSET: "NOTSET", +} + +_loggers = {} +_stream = sys.stderr +_default_fmt = "%(levelname)s:%(name)s:%(message)s" +_default_datefmt = "%Y-%m-%d %H:%M:%S" + + +class LogRecord: + def set(self, name, level, message): + self.name = name + self.levelno = level + self.levelname = _level_dict[level] + self.message = message + self.ct = time.time() + self.msecs = int((self.ct - int(self.ct)) * 1000) + self.asctime = None + + +class Handler: + def __init__(self, level=NOTSET): + self.level = level + self.formatter = None + + def close(self): + pass + + def setLevel(self, level): + self.level = level + + def setFormatter(self, formatter): + self.formatter = formatter + + def format(self, record): + return self.formatter.format(record) + + +class StreamHandler(Handler): + def __init__(self, stream=None): + super().__init__() + self.stream = _stream if stream is None else stream + self.terminator = "\n" + + def close(self): + if hasattr(self.stream, "flush"): + self.stream.flush() + + def emit(self, record): + if record.levelno >= self.level: + self.stream.write(self.format(record) + self.terminator) + + +class FileHandler(StreamHandler): + def __init__(self, filename, mode="a", encoding="UTF-8"): + super().__init__(stream=open(filename, mode=mode, encoding=encoding)) + + def close(self): + super().close() + self.stream.close() + + +class Formatter: + def __init__(self, fmt=None, datefmt=None): + self.fmt = _default_fmt if fmt is None else fmt + self.datefmt = _default_datefmt if datefmt is None else datefmt + + def usesTime(self): + return "asctime" in self.fmt + + def formatTime(self, datefmt, record): + if hasattr(time, "strftime"): + return time.strftime(datefmt, time.localtime(record.ct)) + return None + + def format(self, record): + if self.usesTime(): + record.asctime = self.formatTime(self.datefmt, record) + return self.fmt % { + "name": record.name, + "message": record.message, + "msecs": record.msecs, + "asctime": record.asctime, + "levelname": record.levelname, + } + + +class Logger: + def __init__(self, name, level=NOTSET): + self.name = name + self.level = level + self.handlers = [] + self.record = LogRecord() + + def setLevel(self, level): + self.level = level + + def isEnabledFor(self, level): + return level >= self.getEffectiveLevel() + + def getEffectiveLevel(self): + return self.level or getLogger().level or _DEFAULT_LEVEL + + def log(self, level, msg, *args): + if self.isEnabledFor(level): + if args: + if isinstance(args[0], dict): + args = args[0] + msg = msg % args + self.record.set(self.name, level, msg) + handlers = self.handlers + if not handlers: + handlers = getLogger().handlers + for h in handlers: + h.emit(self.record) + + def debug(self, msg, *args): + self.log(DEBUG, msg, *args) + + def info(self, msg, *args): + self.log(INFO, msg, *args) + + def warning(self, msg, *args): + self.log(WARNING, msg, *args) + + def error(self, msg, *args): + self.log(ERROR, msg, *args) + + def critical(self, msg, *args): + self.log(CRITICAL, msg, *args) + + def exception(self, msg, *args, exc_info=True): + self.log(ERROR, msg, *args) + tb = None + if isinstance(exc_info, BaseException): + tb = exc_info + elif hasattr(sys, "exc_info"): + tb = sys.exc_info()[1] + if tb: + buf = io.StringIO() + sys.print_exception(tb, buf) + self.log(ERROR, buf.getvalue()) + + def addHandler(self, handler): + self.handlers.append(handler) + + def hasHandlers(self): + return len(self.handlers) > 0 + + +def getLogger(name=None): + if name is None: + name = "root" + if name not in _loggers: + _loggers[name] = Logger(name) + if name == "root": + basicConfig() + return _loggers[name] + + +def log(level, msg, *args): + getLogger().log(level, msg, *args) + + +def debug(msg, *args): + getLogger().debug(msg, *args) + + +def info(msg, *args): + getLogger().info(msg, *args) + + +def warning(msg, *args): + getLogger().warning(msg, *args) + + +def error(msg, *args): + getLogger().error(msg, *args) + + +def critical(msg, *args): + getLogger().critical(msg, *args) + + +def exception(msg, *args, exc_info=True): + getLogger().exception(msg, *args, exc_info=exc_info) + + +def shutdown(): + for k, logger in _loggers.items(): + for h in logger.handlers: + h.close() + _loggers.pop(logger, None) + + +def addLevelName(level, name): + _level_dict[level] = name + + +def basicConfig( + filename=None, + filemode="a", + format=None, + datefmt=None, + level=WARNING, + stream=None, + encoding="UTF-8", + force=False, +): + if "root" not in _loggers: + _loggers["root"] = Logger("root") + + logger = _loggers["root"] + + if force or not logger.handlers: + for h in logger.handlers: + h.close() + logger.handlers = [] + + if filename is None: + handler = StreamHandler(stream) + else: + handler = FileHandler(filename, filemode, encoding) + + handler.setLevel(level) + handler.setFormatter(Formatter(format, datefmt)) + + logger.setLevel(level) + logger.addHandler(handler) + + +if hasattr(sys, "atexit"): + sys.atexit(shutdown) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/logging.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/logging.pyi new file mode 100644 index 000000000..856bcccf7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/logging.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete +from micropython import const as const + +CRITICAL: int +ERROR: int +WARNING: int +INFO: int +DEBUG: int +NOTSET: int +_DEFAULT_LEVEL = WARNING +_level_dict: Incomplete +_loggers: Incomplete +_stream: Incomplete +_default_fmt: str +_default_datefmt: str + +class LogRecord: + name: Incomplete + levelno: Incomplete + levelname: Incomplete + message: Incomplete + ct: Incomplete + msecs: Incomplete + asctime: Incomplete + def set(self, name, level, message) -> None: ... + +class Handler: + level: Incomplete + formatter: Incomplete + def __init__(self, level=...) -> None: ... + def close(self) -> None: ... + def setLevel(self, level) -> None: ... + def setFormatter(self, formatter) -> None: ... + def format(self, record): ... + +class StreamHandler(Handler): + stream: Incomplete + terminator: str + def __init__(self, stream=None) -> None: ... + def close(self) -> None: ... + def emit(self, record) -> None: ... + +class FileHandler(StreamHandler): + def __init__(self, filename, mode: str = "a", encoding: str = "UTF-8") -> None: ... + def close(self) -> None: ... + +class Formatter: + fmt: Incomplete + datefmt: Incomplete + def __init__(self, fmt=None, datefmt=None) -> None: ... + def usesTime(self): ... + def formatTime(self, datefmt, record): ... + def format(self, record): ... + +class Logger: + name: Incomplete + level: Incomplete + handlers: Incomplete + record: Incomplete + def __init__(self, name, level=...) -> None: ... + def setLevel(self, level) -> None: ... + def isEnabledFor(self, level): ... + def getEffectiveLevel(self): ... + def log(self, level, msg, *args) -> None: ... + def debug(self, msg, *args) -> None: ... + def info(self, msg, *args) -> None: ... + def warning(self, msg, *args) -> None: ... + def error(self, msg, *args) -> None: ... + def critical(self, msg, *args) -> None: ... + def exception(self, msg, *args, exc_info: bool = True) -> None: ... + def addHandler(self, handler) -> None: ... + def hasHandlers(self): ... + +def getLogger(name=None): ... +def log(level, msg, *args) -> None: ... +def debug(msg, *args) -> None: ... +def info(msg, *args) -> None: ... +def warning(msg, *args) -> None: ... +def error(msg, *args) -> None: ... +def critical(msg, *args) -> None: ... +def exception(msg, *args, exc_info: bool = True) -> None: ... +def shutdown() -> None: ... +def addLevelName(level, name) -> None: ... +def basicConfig( + filename=None, filemode: str = "a", format=None, datefmt=None, level=..., stream=None, encoding: str = "UTF-8", force: bool = False +) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/modules.json new file mode 100644 index 000000000..fe00fde91 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/modules.json @@ -0,0 +1,152 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "ARDUINO_NICLA_VISION", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "cbor2/__init__.py", + "module": "__init__" + }, + { + "file": "cbor2/_decoder.py", + "module": "_decoder" + }, + { + "file": "cbor2/_encoder.py", + "module": "_encoder" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "logging.py", + "module": "logging" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "msgpack.py", + "module": "msgpack" + }, + { + "file": "msgpackrpc.py", + "module": "msgpackrpc" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "se05x/__init__.py", + "module": "__init__" + }, + { + "file": "se05x/iso7816.py", + "module": "iso7816" + }, + { + "file": "se05x/se05x.py", + "module": "se05x" + }, + { + "file": "senml/__init__.py", + "module": "__init__" + }, + { + "file": "senml/senml_base.py", + "module": "senml_base" + }, + { + "file": "senml/senml_pack.py", + "module": "senml_pack" + }, + { + "file": "senml/senml_record.py", + "module": "senml_record" + }, + { + "file": "senml/senml_unit.py", + "module": "senml_unit" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "time.py", + "module": "time" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpack.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpack.py new file mode 100644 index 000000000..3f1f2683c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpack.py @@ -0,0 +1,860 @@ +# u-msgpack-python v2.8.0 - v at sergeev.io +# https://github.com/vsergeev/u-msgpack-python +# +# u-msgpack-python is a lightweight MessagePack serializer and deserializer +# module, compatible with both Python 2 and 3, as well CPython and PyPy +# implementations of Python. u-msgpack-python is fully compliant with the +# latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +# particular, it supports the new binary, UTF-8 string, and application ext +# types. +# +# MIT License +# +# Copyright (c) 2013-2023 vsergeev / Ivan (Vanya) A. Sergeev +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +""" +u-msgpack-python v2.8.0 - v at sergeev.io +https://github.com/vsergeev/u-msgpack-python + +u-msgpack-python is a lightweight MessagePack serializer and deserializer +module, compatible with both Python 2 and 3, as well CPython and PyPy +implementations of Python. u-msgpack-python is fully compliant with the +latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +particular, it supports the new binary, UTF-8 string, and application ext +types. + +License: MIT +""" + +import struct +import collections +import sys +import io + +__version__ = "2.8.0" +"Module version string" + +version = (2, 8, 0) +"Module version tuple" + + +############################################################################## +# Ext Class +############################################################################## + + +# Extension type for application-defined types and data +class Ext(object): + """ + The Ext class facilitates creating a serializable extension object to store + an application-defined type and data byte array. + """ + + def __init__(self, type, data): + """ + Construct a new Ext object. + + Args: + type (int): application-defined type integer + data (bytes): application-defined data byte array + + Raises: + TypeError: + Type is not an integer. + ValueError: + Type is out of range of -128 to 127. + TypeError: + Data is not type 'bytes' (Python 3) or not type 'str' (Python 2). + + Example: + >>> foo = umsgpack.Ext(5, b"\\x01\\x02\\x03") + >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) + '\\x82\\xa7awesome\\xc3\\xadspecial stuff\\xc7\\x03\\x05\\x01\\x02\\x03' + >>> bar = umsgpack.unpackb(_) + >>> print(bar["special stuff"]) + Ext Object (Type: 5, Data: 01 02 03) + """ + # Check type is type int and in range + if not isinstance(type, int): + raise TypeError("ext type is not type integer") + elif not (-(2**7) <= type <= 2**7 - 1): + raise ValueError("ext type value {:d} is out of range (-128 to 127)".format(type)) + # Check data is type bytes or str + elif sys.version_info[0] == 3 and not isinstance(data, bytes): + raise TypeError("ext data is not type 'bytes'") + elif sys.version_info[0] == 2 and not isinstance(data, str): + raise TypeError("ext data is not type 'str'") + + self.type = type + self.data = data + + def __eq__(self, other): + """ + Compare this Ext object with another for equality. + """ + return isinstance(other, self.__class__) and self.type == other.type and self.data == other.data + + def __ne__(self, other): + """ + Compare this Ext object with another for inequality. + """ + return not self.__eq__(other) + + def __str__(self): + """ + String representation of this Ext object. + """ + s = "Ext Object (Type: {:d}, Data: ".format(self.type) + s += " ".join(["0x{:02x}".format(ord(self.data[i : i + 1])) for i in range(min(len(self.data), 8))]) + if len(self.data) > 8: + s += " ..." + s += ")" + return s + + def __hash__(self): + """ + Provide a hash of this Ext object. + """ + return hash((self.type, self.data)) + + +class InvalidString(bytes): + """Subclass of bytes to hold invalid UTF-8 strings.""" + + +############################################################################## +# Ext Serializable Decorator +############################################################################## + +_ext_class_to_type = {} +_ext_type_to_class = {} + + +def ext_serializable(ext_type): + """ + Return a decorator to register a class for automatic packing and unpacking + with the specified Ext type code. The application class should implement a + `packb()` method that returns serialized bytes, and an `unpackb()` class + method or static method that accepts serialized bytes and returns an + instance of the application class. + + Args: + ext_type (int): application-defined Ext type code + + Raises: + TypeError: + Ext type is not an integer. + ValueError: + Ext type is out of range of -128 to 127. + ValueError: + Ext type or class already registered. + """ + + def wrapper(cls): + if not isinstance(ext_type, int): + raise TypeError("Ext type is not type integer") + elif not (-(2**7) <= ext_type <= 2**7 - 1): + raise ValueError("Ext type value {:d} is out of range of -128 to 127".format(ext_type)) + elif ext_type in _ext_type_to_class: + raise ValueError("Ext type {:d} already registered with class {:s}".format(ext_type, repr(_ext_type_to_class[ext_type]))) + elif cls in _ext_class_to_type: + raise ValueError("Class {:s} already registered with Ext type {:d}".format(repr(cls), ext_type)) + + _ext_type_to_class[ext_type] = cls + _ext_class_to_type[cls] = ext_type + + return cls + + return wrapper + + +############################################################################## +# Exceptions +############################################################################## + + +# Base Exception classes +class PackException(Exception): + "Base class for exceptions encountered during packing." + + +class UnpackException(Exception): + "Base class for exceptions encountered during unpacking." + + +# Packing error +class UnsupportedTypeException(PackException): + "Object type not supported for packing." + + +# Unpacking error +class InsufficientDataException(UnpackException): + "Insufficient data to unpack the serialized object." + + +class InvalidStringException(UnpackException): + "Invalid UTF-8 string encountered during unpacking." + + +class UnsupportedTimestampException(UnpackException): + "Unsupported timestamp format encountered during unpacking." + + +class ReservedCodeException(UnpackException): + "Reserved code encountered during unpacking." + + +class UnhashableKeyException(UnpackException): + """ + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + """ + + +class DuplicateKeyException(UnpackException): + "Duplicate key encountered during map unpacking." + + +############################################################################## +# Packing +############################################################################## + +# You may notice struct.pack("B", obj) instead of the simpler chr(obj) in the +# code below. This is to allow for seamless Python 2 and 3 compatibility, as +# chr(obj) has a str return type instead of bytes in Python 3, and +# struct.pack(...) has the right return type in both versions. + + +def _pack_integer(obj, fp, options): + if obj < 0: + if obj >= -32: + fp.write(struct.pack("b", obj)) + elif obj >= -(2 ** (8 - 1)): + fp.write(b"\xd0" + struct.pack("b", obj)) + elif obj >= -(2 ** (16 - 1)): + fp.write(b"\xd1" + struct.pack(">h", obj)) + elif obj >= -(2 ** (32 - 1)): + fp.write(b"\xd2" + struct.pack(">i", obj)) + elif obj >= -(2 ** (64 - 1)): + fp.write(b"\xd3" + struct.pack(">q", obj)) + else: + raise UnsupportedTypeException("huge signed int") + else: + if obj < 128: + fp.write(struct.pack("B", obj)) + elif obj < 2**8: + fp.write(b"\xcc" + struct.pack("B", obj)) + elif obj < 2**16: + fp.write(b"\xcd" + struct.pack(">H", obj)) + elif obj < 2**32: + fp.write(b"\xce" + struct.pack(">I", obj)) + elif obj < 2**64: + fp.write(b"\xcf" + struct.pack(">Q", obj)) + else: + raise UnsupportedTypeException("huge unsigned int") + + +def _pack_nil(obj, fp, options): + fp.write(b"\xc0") + + +def _pack_boolean(obj, fp, options): + fp.write(b"\xc3" if obj else b"\xc2") + + +def _pack_float(obj, fp, options): + float_precision = options.get("force_float_precision", "single") + + if float_precision == "double": + fp.write(b"\xcb" + struct.pack(">d", obj)) + elif float_precision == "single": + fp.write(b"\xca" + struct.pack(">f", obj)) + else: + raise ValueError("invalid float precision") + + +def _pack_string(obj, fp, options): + obj = obj.encode("utf-8") + obj_len = len(obj) + if obj_len < 32: + fp.write(struct.pack("B", 0xA0 | obj_len) + obj) + elif obj_len < 2**8: + fp.write(b"\xd9" + struct.pack("B", obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xda" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xdb" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge string") + + +def _pack_binary(obj, fp, options): + obj_len = len(obj) + if obj_len < 2**8: + fp.write(b"\xc4" + struct.pack("B", obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xc5" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xc6" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge binary string") + + +def _pack_oldspec_raw(obj, fp, options): + obj_len = len(obj) + if obj_len < 32: + fp.write(struct.pack("B", 0xA0 | obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xda" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xdb" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge raw string") + + +def _pack_ext(obj, fp, options): + obj_len = len(obj.data) + if obj_len == 1: + fp.write(b"\xd4" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 2: + fp.write(b"\xd5" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 4: + fp.write(b"\xd6" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 8: + fp.write(b"\xd7" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 16: + fp.write(b"\xd8" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len < 2**8: + fp.write(b"\xc7" + struct.pack("BB", obj_len, obj.type & 0xFF) + obj.data) + elif obj_len < 2**16: + fp.write(b"\xc8" + struct.pack(">HB", obj_len, obj.type & 0xFF) + obj.data) + elif obj_len < 2**32: + fp.write(b"\xc9" + struct.pack(">IB", obj_len, obj.type & 0xFF) + obj.data) + else: + raise UnsupportedTypeException("huge ext data") + + +def _pack_array(obj, fp, options): + obj_len = len(obj) + if obj_len < 16: + fp.write(struct.pack("B", 0x90 | obj_len)) + elif obj_len < 2**16: + fp.write(b"\xdc" + struct.pack(">H", obj_len)) + elif obj_len < 2**32: + fp.write(b"\xdd" + struct.pack(">I", obj_len)) + else: + raise UnsupportedTypeException("huge array") + + for e in obj: + pack(e, fp, **options) + + +def _pack_map(obj, fp, options): + obj_len = len(obj) + if obj_len < 16: + fp.write(struct.pack("B", 0x80 | obj_len)) + elif obj_len < 2**16: + fp.write(b"\xde" + struct.pack(">H", obj_len)) + elif obj_len < 2**32: + fp.write(b"\xdf" + struct.pack(">I", obj_len)) + else: + raise UnsupportedTypeException("huge array") + + for k, v in obj.items(): + pack(k, fp, **options) + pack(v, fp, **options) + + +# Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type +def pack(obj, fp, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + None + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> f = open('test.bin', 'wb') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + """ + ext_handlers = options.get("ext_handlers") + + if obj is None: + _pack_nil(obj, fp, options) + elif ext_handlers and obj.__class__ in ext_handlers: + _pack_ext(ext_handlers[obj.__class__](obj), fp, options) + elif obj.__class__ in _ext_class_to_type: + try: + _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) + elif isinstance(obj, bool): + _pack_boolean(obj, fp, options) + elif isinstance(obj, int): + _pack_integer(obj, fp, options) + elif isinstance(obj, float): + _pack_float(obj, fp, options) + elif isinstance(obj, str): + _pack_string(obj, fp, options) + elif isinstance(obj, bytes): + _pack_binary(obj, fp, options) + elif isinstance(obj, (list, tuple)): + _pack_array(obj, fp, options) + elif isinstance(obj, dict): + _pack_map(obj, fp, options) + elif isinstance(obj, Ext): + _pack_ext(obj, fp, options) + elif ext_handlers: + # Linear search for superclass + t = next((t for t in ext_handlers.keys() if isinstance(obj, t)), None) + if t: + _pack_ext(ext_handlers[t](obj), fp, options) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + elif _ext_class_to_type: + # Linear search for superclass + t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) + if t: + try: + _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + + +def packb(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + bytes: Serialized MessagePack bytes + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + b'\\x82\\xa7compact\\xc3\\xa6schema\\x00' + """ + fp = io.BytesIO() + pack(obj, fp, **options) + return fp.getvalue() + + +############################################################################# +# Unpacking +############################################################################# + + +def _read_except(fp, n): + if n == 0: + return b"" + + data = fp.read(n) + if len(data) == 0: + raise InsufficientDataException() + + while len(data) < n: + chunk = fp.read(n - len(data)) + if len(chunk) == 0: + raise InsufficientDataException() + + data += chunk + + return data + + +def _unpack_integer(code, fp, options): + if (ord(code) & 0xE0) == 0xE0: + return struct.unpack("b", code)[0] + elif code == b"\xd0": + return struct.unpack("b", _read_except(fp, 1))[0] + elif code == b"\xd1": + return struct.unpack(">h", _read_except(fp, 2))[0] + elif code == b"\xd2": + return struct.unpack(">i", _read_except(fp, 4))[0] + elif code == b"\xd3": + return struct.unpack(">q", _read_except(fp, 8))[0] + elif (ord(code) & 0x80) == 0x00: + return struct.unpack("B", code)[0] + elif code == b"\xcc": + return struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xcd": + return struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xce": + return struct.unpack(">I", _read_except(fp, 4))[0] + elif code == b"\xcf": + return struct.unpack(">Q", _read_except(fp, 8))[0] + raise Exception("logic error, not int: 0x{:02x}".format(ord(code))) + + +def _unpack_reserved(code, fp, options): + if code == b"\xc1": + raise ReservedCodeException("encountered reserved code: 0x{:02x}".format(ord(code))) + raise Exception("logic error, not reserved code: 0x{:02x}".format(ord(code))) + + +def _unpack_nil(code, fp, options): + if code == b"\xc0": + return None + raise Exception("logic error, not nil: 0x{:02x}".format(ord(code))) + + +def _unpack_boolean(code, fp, options): + if code == b"\xc2": + return False + elif code == b"\xc3": + return True + raise Exception("logic error, not boolean: 0x{:02x}".format(ord(code))) + + +def _unpack_float(code, fp, options): + if code == b"\xca": + return struct.unpack(">f", _read_except(fp, 4))[0] + elif code == b"\xcb": + return struct.unpack(">d", _read_except(fp, 8))[0] + raise Exception("logic error, not float: 0x{:02x}".format(ord(code))) + + +def _unpack_string(code, fp, options): + if (ord(code) & 0xE0) == 0xA0: + length = ord(code) & ~0xE0 + elif code == b"\xd9": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xda": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdb": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not string: 0x{:02x}".format(ord(code))) + + data = _read_except(fp, length) + try: + return bytes.decode(data, "utf-8") + except Exception: + if options.get("allow_invalid_utf8", True): + return InvalidString(data) + raise InvalidStringException("unpacked string is invalid utf-8") + + +def _unpack_binary(code, fp, options): + if code == b"\xc4": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xc5": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xc6": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not binary: 0x{:02x}".format(ord(code))) + + return _read_except(fp, length) + + +def _unpack_ext(code, fp, options): + if code == b"\xd4": + length = 1 + elif code == b"\xd5": + length = 2 + elif code == b"\xd6": + length = 4 + elif code == b"\xd7": + length = 8 + elif code == b"\xd8": + length = 16 + elif code == b"\xc7": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xc8": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xc9": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not ext: 0x{:02x}".format(ord(code))) + + ext_type = struct.unpack("b", _read_except(fp, 1))[0] + ext_data = _read_except(fp, length) + + # Unpack with ext handler, if we have one + ext_handlers = options.get("ext_handlers") + if ext_handlers and ext_type in ext_handlers: + return ext_handlers[ext_type](Ext(ext_type, ext_data)) + + # Unpack with ext classes, if type is registered + if ext_type in _ext_type_to_class: + try: + return _ext_type_to_class[ext_type].unpackb(ext_data) + except AttributeError: + raise NotImplementedError( + "Ext serializable class {:s} is missing implementation of unpackb()".format(repr(_ext_type_to_class[ext_type])) + ) + + return Ext(ext_type, ext_data) + + +def _unpack_array(code, fp, options): + if (ord(code) & 0xF0) == 0x90: + length = ord(code) & ~0xF0 + elif code == b"\xdc": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdd": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not array: 0x{:02x}".format(ord(code))) + + if options.get("use_tuple"): + return tuple((_unpack(fp, options) for i in range(length))) + + return [_unpack(fp, options) for i in range(length)] + + +def _deep_list_to_tuple(obj): + if isinstance(obj, list): + return tuple([_deep_list_to_tuple(e) for e in obj]) + return obj + + +def _unpack_map(code, fp, options): + if (ord(code) & 0xF0) == 0x80: + length = ord(code) & ~0xF0 + elif code == b"\xde": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdf": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not map: 0x{:02x}".format(ord(code))) + + d = {} if not options.get("use_ordered_dict") else collections.OrderedDict() + for _ in range(length): + # Unpack key + k = _unpack(fp, options) + + if isinstance(k, list): + # Attempt to convert list into a hashable tuple + k = _deep_list_to_tuple(k) + try: + hash(k) + except Exception: + raise UnhashableKeyException('encountered unhashable key: "{:s}" ({:s})'.format(str(k), str(type(k)))) + if k in d: + raise DuplicateKeyException('encountered duplicate key: "{:s}" ({:s})'.format(str(k), str(type(k)))) + + # Unpack value + v = _unpack(fp, options) + + try: + d[k] = v + except TypeError: + raise UnhashableKeyException('encountered unhashable key: "{:s}"'.format(str(k))) + return d + + +def _unpack(fp, options): + code = _read_except(fp, 1) + return _unpack_dispatch_table[code](code, fp, options) + + +def unpack(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {'compact': True, 'schema': 0} + """ + return _unpack(fp, options) + + +# For Python 3, expects a bytes object +def unpackb(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s (bytes, bytearray): serialized MessagePack bytes + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + TypeError: + Packed data type is neither 'bytes' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\\x82\\xa7compact\\xc3\\xa6schema\\x00') + {'compact': True, 'schema': 0} + """ + if not isinstance(s, (bytes, bytearray)): + raise TypeError("packed data must be type 'bytes' or 'bytearray'") + return _unpack(io.BytesIO(s), options) + + +############################################################################# +# Module Initialization +############################################################################# + + +def __init(): + global _unpack_dispatch_table + # Build a dispatch table for fast lookup of unpacking function + _unpack_dispatch_table = {} + # Fix uint + for code in range(0, 0x7F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fix map + for code in range(0x80, 0x8F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_map + # Fix array + for code in range(0x90, 0x9F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_array + # Fix str + for code in range(0xA0, 0xBF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Nil + _unpack_dispatch_table[b"\xc0"] = _unpack_nil + # Reserved + _unpack_dispatch_table[b"\xc1"] = _unpack_reserved + # Boolean + _unpack_dispatch_table[b"\xc2"] = _unpack_boolean + _unpack_dispatch_table[b"\xc3"] = _unpack_boolean + # Bin + for code in range(0xC4, 0xC6 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_binary + # Ext + for code in range(0xC7, 0xC9 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # Float + _unpack_dispatch_table[b"\xca"] = _unpack_float + _unpack_dispatch_table[b"\xcb"] = _unpack_float + # Uint + for code in range(0xCC, 0xCF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Int + for code in range(0xD0, 0xD3 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fixext + for code in range(0xD4, 0xD8 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # String + for code in range(0xD9, 0xDB + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Array + _unpack_dispatch_table[b"\xdc"] = _unpack_array + _unpack_dispatch_table[b"\xdd"] = _unpack_array + # Map + _unpack_dispatch_table[b"\xde"] = _unpack_map + _unpack_dispatch_table[b"\xdf"] = _unpack_map + # Negative fixint + for code in range(0xE0, 0xFF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + + +__init() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpack.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpack.pyi new file mode 100644 index 000000000..2dec10602 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpack.pyi @@ -0,0 +1,278 @@ +from _typeshed import Incomplete + +__version__: str +version: Incomplete + +class Ext: + """ + The Ext class facilitates creating a serializable extension object to store + an application-defined type and data byte array. + """ + + type: Incomplete + data: Incomplete + def __init__(self, type, data) -> None: + """ + Construct a new Ext object. + + Args: + type (int): application-defined type integer + data (bytes): application-defined data byte array + + Raises: + TypeError: + Type is not an integer. + ValueError: + Type is out of range of -128 to 127. + TypeError: + Data is not type \'bytes\' (Python 3) or not type \'str\' (Python 2). + + Example: + >>> foo = umsgpack.Ext(5, b"\\x01\\x02\\x03") + >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) + \'\\x82\\xa7awesome\\xc3\\xadspecial stuff\\xc7\\x03\\x05\\x01\\x02\\x03\' + >>> bar = umsgpack.unpackb(_) + >>> print(bar["special stuff"]) + Ext Object (Type: 5, Data: 01 02 03) + """ + def __eq__(self, other): + """ + Compare this Ext object with another for equality. + """ + def __ne__(self, other): + """ + Compare this Ext object with another for inequality. + """ + def __str__(self) -> str: + """ + String representation of this Ext object. + """ + def __hash__(self): + """ + Provide a hash of this Ext object. + """ + +class InvalidString(bytes): + """Subclass of bytes to hold invalid UTF-8 strings.""" + +_ext_class_to_type: Incomplete +_ext_type_to_class: Incomplete + +def ext_serializable(ext_type): + """ + Return a decorator to register a class for automatic packing and unpacking + with the specified Ext type code. The application class should implement a + `packb()` method that returns serialized bytes, and an `unpackb()` class + method or static method that accepts serialized bytes and returns an + instance of the application class. + + Args: + ext_type (int): application-defined Ext type code + + Raises: + TypeError: + Ext type is not an integer. + ValueError: + Ext type is out of range of -128 to 127. + ValueError: + Ext type or class already registered. + """ + +class PackException(Exception): + """Base class for exceptions encountered during packing.""" + +class UnpackException(Exception): + """Base class for exceptions encountered during unpacking.""" + +class UnsupportedTypeException(PackException): + """Object type not supported for packing.""" + +class InsufficientDataException(UnpackException): + """Insufficient data to unpack the serialized object.""" + +class InvalidStringException(UnpackException): + """Invalid UTF-8 string encountered during unpacking.""" + +class UnsupportedTimestampException(UnpackException): + """Unsupported timestamp format encountered during unpacking.""" + +class ReservedCodeException(UnpackException): + """Reserved code encountered during unpacking.""" + +class UnhashableKeyException(UnpackException): + """ + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + """ + +class DuplicateKeyException(UnpackException): + """Duplicate key encountered during map unpacking.""" + +def _pack_integer(obj, fp, options) -> None: ... +def _pack_nil(obj, fp, options) -> None: ... +def _pack_boolean(obj, fp, options) -> None: ... +def _pack_float(obj, fp, options) -> None: ... +def _pack_string(obj, fp, options) -> None: ... +def _pack_binary(obj, fp, options) -> None: ... +def _pack_oldspec_raw(obj, fp, options) -> None: ... +def _pack_ext(obj, fp, options) -> None: ... +def _pack_array(obj, fp, options) -> None: ... +def _pack_map(obj, fp, options) -> None: ... +def pack(obj, fp, **options) -> None: + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + None + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> f = open(\'test.bin\', \'wb\') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + """ + +def packb(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + bytes: Serialized MessagePack bytes + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + b\'\\x82\\xa7compact\\xc3\\xa6schema\\x00\' + """ + +def _read_except(fp, n): ... +def _unpack_integer(code, fp, options): ... +def _unpack_reserved(code, fp, options) -> None: ... +def _unpack_nil(code, fp, options) -> None: ... +def _unpack_boolean(code, fp, options): ... +def _unpack_float(code, fp, options): ... +def _unpack_string(code, fp, options): ... +def _unpack_binary(code, fp, options): ... +def _unpack_ext(code, fp, options): ... +def _unpack_array(code, fp, options): ... +def _deep_list_to_tuple(obj): ... +def _unpack_map(code, fp, options): ... +def _unpack(fp, options): ... +def unpack(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {'compact': True, 'schema': 0} + """ + +def unpackb(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s (bytes, bytearray): serialized MessagePack bytes + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + TypeError: + Packed data type is neither 'bytes' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\\x82\\xa7compact\\xc3\\xa6schema\\x00') + {'compact': True, 'schema': 0} + """ + +def __init() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpackrpc.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpackrpc.py new file mode 100644 index 000000000..e65c32e83 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpackrpc.py @@ -0,0 +1,202 @@ +# This file is part of the msgpack-rpc module. +# Copyright (c) 2023 Arduino SA +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# MessagePack RPC protocol implementation for MicroPython. +# https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md + +import logging +import openamp +import msgpack +from micropython import const +from io import BytesIO +from time import sleep_ms, ticks_ms, ticks_diff + +_MSG_TYPE_REQUEST = 0 +_MSG_TYPE_RESPONSE = 1 +_MSG_TYPE_NOTIFY = 2 + + +def log_level_enabled(level): + return logging.getLogger().isEnabledFor(level) + + +class Future: + def __init__(self, msgid, msgbuf, fname, fargs): + self.msgid = msgid + self.msgbuf = msgbuf + self.fname = fname + self.fargs = fargs + + def join(self, timeout=0): + if log_level_enabled(logging.DEBUG): + logging.debug(f"join {self.fname}()") + + if timeout > 0: + t = ticks_ms() + + while self.msgid not in self.msgbuf: + if timeout > 0 and ticks_diff(ticks_ms(), t) > timeout: + raise OSError(f"Timeout joining function {self.fname}") + sleep_ms(100) + + obj = self.msgbuf.pop(self.msgid) + if obj[2] is not None: + raise (OSError(obj[2])) + + if log_level_enabled(logging.DEBUG): + logging.debug(f"call {self.fname}({self.fargs}) => {obj}") + return obj[3] + + +class MsgPackIO: + def __init__(self): + self.stream = BytesIO() + + def feed(self, data): + offset = self.stream.tell() + self.stream.write(data) + self.stream.seek(offset) + + def readable(self): + if self.stream.read(1): + offset = self.stream.tell() + self.stream.seek(offset - 1) + return True + return False + + def truncate(self): + if self.readable(): + offset = self.stream.tell() + self.stream = BytesIO(self.stream.getvalue()[offset:]) + + def __iter__(self): + return self + + def __next__(self): + offset = self.stream.tell() + try: + obj = msgpack.unpack(self.stream) + self.truncate() + return obj + except Exception: + self.stream.seek(offset) + raise StopIteration + + +class MsgPackRPC: + def __init__(self, streaming=False): + """ + Create a MsgPack RPC object. + streaming: If True, messages can span multiple buffers, otherwise a buffer contains + exactly one full message. Note streaming mode is slower, so it should be disabled + if it's not needed. + """ + self.epts = {} + self.msgid = 0 + self.msgbuf = {} + self.msgio = MsgPackIO() if streaming else None + self.callables = {} + + def _bind_callback(self, src, name): + if log_level_enabled(logging.INFO): + logging.info(f'New service announcement src: {src} name: "{name}"') + self.epts[name] = openamp.Endpoint(name, self._recv_callback, dest=src) + self.epts[name].send(b"\x00") + + def _recv_callback(self, src, data): + if log_level_enabled(logging.DEBUG): + logging.debug(f"Received message on endpoint: {src} data: {bytes(data)}") + + if self.msgio is None: + obj = msgpack.unpackb(data) + self._process_unpacked_obj(obj) + else: + self.msgio.feed(data) + for obj in self.msgio: + self._process_unpacked_obj(obj) + + def _process_unpacked_obj(self, obj): + if obj[0] == _MSG_TYPE_RESPONSE: + self.msgbuf[obj[1]] = obj + elif obj[0] == _MSG_TYPE_REQUEST: + self._dispatch(obj[1], obj[2], obj[-1]) + if log_level_enabled(logging.DEBUG): + logging.debug(f"Unpacked {type(obj)} val: {obj}") + + def _send_msg(self, msgid, msgtype, fname, fargs, **kwargs): + timeout = kwargs.pop("timeout", 1000) + endpoint = kwargs.pop("endpoint", "rpc") + self.epts[endpoint].send(msgpack.packb([msgtype, msgid, fname, fargs]), timeout=timeout) + if msgtype == _MSG_TYPE_REQUEST: + self.msgid += 1 + return Future(msgid, self.msgbuf, fname, fargs) + + def _dispatch(self, msgid, fname, fargs): + retobj = None + error = None + + if fname in self.callables: + retobj = self.callables[fname](*fargs) + else: + error = "Unbound function called %s" % (fname) + + self._send_msg(msgid, _MSG_TYPE_RESPONSE, error, retobj) + + def bind(self, name, obj): + """ + Bind a callable or an object to a name. + name: The name to which the callable or object is bound. + obj: A callable or an object to bind to the name. If an object is passed, all of its + public methods will be bound to their respective qualified names. + """ + if callable(obj): + # Bind a single callable to its name. + self.callables[name] = obj + else: + # Bind all public methods of an object to their respective qualified names. + for k, v in obj.__class__.__dict__.items(): + if callable(v) and not k.startswith("_"): + self.callables[name + "." + k] = getattr(obj, k) + + def start(self, firmware=None, num_channels=2, timeout=3000): + """ + Initializes OpenAMP, loads the remote processor's firmware and starts. + firmware: A path to an elf file stored in the filesystem, or an address to an entry point in flash. + num_channels: The number of channels to wait for the remote processor to + create before starting to communicate with it. + timeout: How long to wait for the remote processor to start, 0 means forever. + """ + # Initialize OpenAMP and set the New Service callback. + openamp.new_service_callback(self._bind_callback) + + # Keep a reference to the remote processor object, to stop the GC from collecting + # it, which would call the finaliser and shut down the remote processor while it's + # still being used. + self.rproc = openamp.RemoteProc(firmware) + self.rproc.start() + + # Wait for remote processor to announce the end points. + t = ticks_ms() + while len(self.epts) != num_channels: + if timeout > 0 and ticks_diff(ticks_ms(), t) > timeout: + raise OSError("timeout waiting for the remote processor to start") + sleep_ms(10) + + # Introduce a brief delay to allow the M4 sufficient time + # to bind remote functions before invoking them. + sleep_ms(100) + + def call(self, fname, *args, **kwargs): + """ + Synchronous call. The client is blocked until the RPC is finished. + """ + return self.call_async(fname, *args, *kwargs).join() + + def call_async(self, fname, *args, **kwargs): + """ + Asynchronous call. The client returns a Future object immediately. + """ + return self._send_msg(self.msgid, _MSG_TYPE_REQUEST, fname, list(args), *kwargs) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpackrpc.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpackrpc.pyi new file mode 100644 index 000000000..25c365b6d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/msgpackrpc.pyi @@ -0,0 +1,68 @@ +from _typeshed import Incomplete +from micropython import const as const + +_MSG_TYPE_REQUEST: int +_MSG_TYPE_RESPONSE: int +_MSG_TYPE_NOTIFY: int + +def log_level_enabled(level): ... + +class Future: + msgid: Incomplete + msgbuf: Incomplete + fname: Incomplete + fargs: Incomplete + def __init__(self, msgid, msgbuf, fname, fargs) -> None: ... + def join(self, timeout: int = 0): ... + +class MsgPackIO: + stream: Incomplete + def __init__(self) -> None: ... + def feed(self, data) -> None: ... + def readable(self): ... + def truncate(self) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class MsgPackRPC: + epts: Incomplete + msgid: int + msgbuf: Incomplete + msgio: Incomplete + callables: Incomplete + def __init__(self, streaming: bool = False) -> None: + """ + Create a MsgPack RPC object. + streaming: If True, messages can span multiple buffers, otherwise a buffer contains + exactly one full message. Note streaming mode is slower, so it should be disabled + if it's not needed. + """ + def _bind_callback(self, src, name) -> None: ... + def _recv_callback(self, src, data) -> None: ... + def _process_unpacked_obj(self, obj) -> None: ... + def _send_msg(self, msgid, msgtype, fname, fargs, **kwargs): ... + def _dispatch(self, msgid, fname, fargs) -> None: ... + def bind(self, name, obj) -> None: + """ + Bind a callable or an object to a name. + name: The name to which the callable or object is bound. + obj: A callable or an object to bind to the name. If an object is passed, all of its + public methods will be bound to their respective qualified names. + """ + rproc: Incomplete + def start(self, firmware=None, num_channels: int = 2, timeout: int = 3000) -> None: + """ + Initializes OpenAMP, loads the remote processor's firmware and starts. + firmware: A path to an elf file stored in the filesystem, or an address to an entry point in flash. + num_channels: The number of channels to wait for the remote processor to + create before starting to communicate with it. + timeout: How long to wait for the remote processor to start, 0 means forever. + """ + def call(self, fname, *args, **kwargs): + """ + Synchronous call. The client is blocked until the RPC is finished. + """ + def call_async(self, fname, *args, **kwargs): + """ + Asynchronous call. The client returns a Future object immediately. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/__init__.py new file mode 100644 index 000000000..c27dc08aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/__init__.py @@ -0,0 +1,22 @@ +from .se05x import SE05X # noqa +from .iso7816 import SmartCard # noqa +from micropython import const + +# Secure Object Types. +EC_KEY = 0x01 +AES_KEY = 0x03 +DES_KEY = 0x04 +HMAC_KEY = 0x05 +BINARY = 0x06 +USERID = 0x07 +CURVE = 0x0B +SIGNATURE = 0x0C +MAC = 0x0D +CIPHER = 0x0E + +# Supported EC curves. +EC_CURVE_NIST_P192 = 0x01 +EC_CURVE_NIST_P224 = 0x02 +EC_CURVE_NIST_P256 = 0x03 +EC_CURVE_NIST_P384 = 0x04 +EC_CURVE_NIST_P521 = 0x05 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/__init__.pyi new file mode 100644 index 000000000..aedcefce8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/__init__.pyi @@ -0,0 +1,19 @@ +from .iso7816 import SmartCard as SmartCard +from .se05x import SE05X as SE05X +from micropython import const as const + +EC_KEY: int +AES_KEY: int +DES_KEY: int +HMAC_KEY: int +BINARY: int +USERID: int +CURVE: int +SIGNATURE: int +MAC: int +CIPHER: int +EC_CURVE_NIST_P192: int +EC_CURVE_NIST_P224: int +EC_CURVE_NIST_P256: int +EC_CURVE_NIST_P384: int +EC_CURVE_NIST_P521: int diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/iso7816.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/iso7816.py new file mode 100644 index 000000000..e8d874a0c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/iso7816.py @@ -0,0 +1,382 @@ +# This file is part of the se05x package. +# Copyright (c) 2024 Arduino SA +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# An implementation of ISO7816-3/4 standards. +import struct +import logging +from micropython import const +from time import sleep + +# PCB bits +_NAD_OFFSET = 0 +_PCB_OFFSET = 1 +_LEN_OFFSET = 2 +_INF_OFFSET = 3 + +# Blocks +_I_BLOCK = 0x00 +_I_BLOCK_N = 6 +_I_BLOCK_M = 5 + +_S_BLOCK = 0xC0 +_S_BLOCK_REQ = 0x3F + +_R_BLOCK = 0x80 +_R_BLOCK_N = 4 +_R_BLOCK_ERR = 0x03 + +# S-Block request/response +_RESYNC_REQ = 0x00 +_IFS_REQ = 0x01 +_ABORT_REQ = 0x02 +_WTX_REQ = 0x03 +_END_SESSION_REQ = 0x05 +_CHIP_RESET_REQ = 0x06 +_GET_ATR_REQ = 0x07 +_SOFT_RESET_REQ = 0x0F + +_CLA_ISO7816 = 0x00 +_INS_GP_SELECT = 0xA4 + +_STATE_IBLK = 0 +_STATE_SBLK = 1 +_STATE_SEND = 2 +_STATE_RECV = 3 +_STATE_WAIT = 4 +_STATE_WWTX = 5 +_STATE_DONE = 6 + + +def log_enabled(level): + return logging.getLogger().isEnabledFor(level) + + +class SmartCard: + def __init__(self, bus, nad, aid): + self.seq = 0 + self.bus = bus + self.sad = nad & 0xF0 + self.dad = nad & 0x0F + self.aid = aid + self.atr = None + + # TODO: Optimize these + self.w_buf = memoryview(bytearray(512)) + self.r_buf = memoryview(bytearray(512)) + self.s_buf = memoryview(bytearray(32)) + self.apdu_buf = memoryview(bytearray(512)) + + self.block_name = {_I_BLOCK: "I-Block", _R_BLOCK: "R-Block", _S_BLOCK: "S-Block"} + self.state_name = { + _STATE_IBLK: "IBLK", + _STATE_SBLK: "SBLK", + _STATE_SEND: "SEND", + _STATE_RECV: "RECV", + _STATE_WAIT: "WAIT", + _STATE_WWTX: "WWTX", + _STATE_DONE: "DONE", + } + self.apdu_status = { + 0x6700: "Wrong length", + 0x6985: "Conditions not satisfied", + 0x6982: "Security status not satisfied", + 0x6A80: "Wrong data", + 0x6984: "Data invalid", + 0x6986: "Command not allowed", + 0x6A82: "File not found", + 0x6A84: "File full", + 0x6D00: "Invalid or not supported instruction code.", + } + + def _block_type(self, pcb): + return _I_BLOCK if pcb & 0x80 == 0 else pcb & 0xC0 + + def _block_size(self, buf): + # NAD, PCB, LEN, INF[LEN], CRC[2] + return 3 + buf[_LEN_OFFSET] + 2 + + def _block_crc16(self, prologue, data, poly=0x8408, crc=0xFFFF): + # Calculate prologue checksum + for i in prologue: + crc ^= i + for bit in range(8): + crc = (crc >> 1) ^ poly if crc & 0x1 else crc >> 1 + + # Calculate data checksum + for i in data: + crc ^= i + for bit in range(8): + crc = (crc >> 1) ^ poly if crc & 0x1 else crc >> 1 + crc ^= 0xFFFF + return ((crc & 0xFF) << 8) | ((crc >> 8) & 0xFF) + + def _block_write(self, buf, delay=0): + size = self._block_size(buf) + self.bus.write(buf[0:size]) + + def _block_print(self, txrx, *args): + if len(args) == 1: + buf = args[0] + nad, pcb, bsize = buf[_NAD_OFFSET : _LEN_OFFSET + 1] + crc = buf[_LEN_OFFSET + bsize + 1] << 8 | buf[_LEN_OFFSET + bsize + 2] + else: + nad, pcb, bsize, crc, buf = args + btype = self._block_type(pcb) + bname = self.block_name[btype] + boffs = _INF_OFFSET if len(args) == 1 else 0 + seq = (pcb >> _I_BLOCK_N) & 1 if btype == _I_BLOCK else (pcb >> _R_BLOCK_N) & 1 + if log_enabled(logging.DEBUG): + logging.debug(f"{'Tx' if txrx else 'Rx'}: {bname} NAD: 0x{nad:X} PCB: 0x{pcb:X} LEN: {bsize} SEQ: {seq} CRC: 0x{crc:X}") + buf_hex = "".join(f"{b:02X}" for b in buf[boffs : boffs + bsize]) + logging.debug(f"RAW: {nad:02X}{pcb:02X}{bsize:02X}{buf_hex}{crc:04X}") + + def _block_new(self, buf, btype, **kwargs): + data = kwargs.get("data", None) + bsize = 0 if data is None else len(data) + buf[_NAD_OFFSET] = self.sad | self.dad + buf[_PCB_OFFSET] = btype + buf[_LEN_OFFSET] = bsize + if btype == _S_BLOCK: + buf[_PCB_OFFSET] |= kwargs["request"] + elif btype == _I_BLOCK: + buf[_PCB_OFFSET] |= self.seq << _I_BLOCK_N + buf[_PCB_OFFSET] |= kwargs["chained"] << _I_BLOCK_M + elif btype == _R_BLOCK: + buf[_PCB_OFFSET] |= self.seq << _R_BLOCK_N + buf[_PCB_OFFSET] |= kwargs["error"] & _R_BLOCK_ERR + if bsize: + buf[_INF_OFFSET : _INF_OFFSET + bsize] = data + # Calculate and set CRC + crc = self._block_crc16(buf[0:_INF_OFFSET], buf[_INF_OFFSET : _INF_OFFSET + bsize]) + buf[_LEN_OFFSET + bsize + 1] = (crc >> 8) & 0xFF + buf[_LEN_OFFSET + bsize + 2] = (crc >> 0) & 0xFF + # Toggle I-Block sequence + if btype == _I_BLOCK: + self.seq = self.seq ^ 1 + return buf + + def _send_block(self, btype, arg, retry=25, backoff=1.2): + r_offs = 0 + w_offs = 0 + retry_delay = 1 / 1000 + next_state = _STATE_SBLK if btype == _S_BLOCK else _STATE_IBLK + + while retry: + if log_enabled(logging.DEBUG): + logging.debug(f"STATE: {self.state_name[next_state]} retry: {retry}") + if next_state == _STATE_SBLK: + next_state = _STATE_SEND + prev_state = _STATE_RECV + block = self._block_new(self.w_buf, _S_BLOCK, request=arg) + elif next_state == _STATE_IBLK: + next_state = _STATE_SEND + prev_state = _STATE_RECV + remain = len(arg) - w_offs + bsize = min(remain, self.atr["IFSC"]) + chained = int(remain > self.atr["IFSC"]) + block = self._block_new(self.w_buf, _I_BLOCK, chained=chained, data=arg[w_offs : w_offs + bsize]) + w_offs += bsize + elif next_state == _STATE_SEND: + try: + self._block_write(block) + next_state = prev_state + if log_enabled(logging.DEBUG): + self._block_print(True, block) + except Exception: + retry -= 1 + elif next_state == _STATE_RECV: + try: + # Read NAD, PCB, LEN, information (if present) and CRC. + nad, pcb, bsize = self.bus.read(self.s_buf[0:3]) + if bsize: + self.bus.read(self.r_buf[r_offs : r_offs + bsize]) + crc = int.from_bytes(self.bus.read(self.s_buf[3:5]), "big") + except Exception: + retry -= 1 + next_state = _STATE_WAIT + prev_state = _STATE_RECV + continue + + # Check NAD and CRC. + exp = self._block_crc16(self.s_buf[0:3], self.r_buf[r_offs : r_offs + bsize]) + if nad != (self.sad >> 4) | (self.dad << 4) or crc != exp: + retry -= 1 + next_state = _STATE_SEND + prev_state = _STATE_RECV + block = self._block_new(self.s_buf, _R_BLOCK, error=1) + continue + + if log_enabled(logging.DEBUG): + self._block_print(False, nad, pcb, bsize, crc, self.r_buf[r_offs : r_offs + bsize]) + + # Process block. + btype = self._block_type(pcb) + if btype == _R_BLOCK: + # Retransmit last block if error, or continue block chain. + next_state = _STATE_SEND if pcb & _R_BLOCK_ERR else _STATE_IBLK + prev_state = _STATE_RECV + continue + + if btype == _I_BLOCK: + # Acknowledge I-Block in block chain with R(N(R)). + if pcb & (1 << _I_BLOCK_M): + next_state = _STATE_SEND + prev_state = _STATE_RECV + block = self._block_new(self.s_buf, _R_BLOCK, error=0) + else: + next_state = _STATE_DONE + # Add current I-Block INF size (could be 0). + r_offs += bsize + continue + + if btype == _S_BLOCK: + if pcb & _S_BLOCK_REQ == _RESYNC_REQ: + # Respond to a resync request. + self.seq = 0 + next_state = _STATE_SEND + prev_state = _STATE_RECV + block = self._block_new(self.s_buf, _S_BLOCK, request=_RESYNC_REQ & 0x20) + elif pcb & _S_BLOCK_REQ == _WTX_REQ: + # Respond to a WTX request. + next_state = _STATE_SEND + prev_state = _STATE_WWTX + wtx_delay = self.r_buf[r_offs] * self.atr["BWT"] / 1000 + block = self._block_new(self.s_buf, _S_BLOCK, request=_WTX_REQ & 0x20) + else: + # Add current S-Block INF size (could be 0). + r_offs += bsize + next_state = _STATE_DONE + continue + elif next_state == _STATE_WWTX: + sleep(wtx_delay) + next_state = _STATE_RECV + elif next_state == _STATE_WAIT: + sleep(retry_delay) + retry_delay *= backoff + next_state = prev_state + elif next_state == _STATE_DONE: + return self.r_buf[0:r_offs] + + if retry == 0: + raise RuntimeError("_send_block failed") + + def send_apdu(self, cla, ins, p1, p2, data=None, le=0): + size = 4 + self.apdu_buf[0] = cla + self.apdu_buf[1] = ins + self.apdu_buf[2] = p1 + self.apdu_buf[3] = p2 + if data is not None: + size = len(data) + self.apdu_buf[4] = size + self.apdu_buf[5 : 5 + size] = data + self.apdu_buf[5 + size] = 0x00 + size += 5 + + # Send APDU in I-Block + resp = self._send_block(_I_BLOCK, self.apdu_buf[0:size]) + + # Check response TPDU status + status = int.from_bytes(resp[-2:], "big") + if status != 0x9000: + raise RuntimeError("APDU Error: " + self.apdu_status.get(status, f"Unknown 0x{status:X}")) + + # Return data bytes, if any, or the status. + if len(resp) == 2: + return status + return resp[2 + (0 if resp[1] <= 0x7F else resp[1] & 0x0F) : -2] + + def reset(self): + self.seq = 0 + atr_raw = self._send_block(_S_BLOCK, _SOFT_RESET_REQ) + if self.atr is None: + self.atr = self._parse_atrs(atr_raw) + if log_enabled(logging.INFO): + self._dump_atrs(self.atr) + # Select applet + self.send_apdu(_CLA_ISO7816, _INS_GP_SELECT, 0x04, 0x00, self.aid, le=True) + + def resync(self): + self._send_block(_S_BLOCK, _RESYNC_REQ) + self.seq = 0 + + def _parse_atrs(self, atr_bytes): + atr = {} + # PVER - 1 byte + atr["PVER"] = atr_bytes[0] + # VID - 5 bytes + atr["VID"] = atr_bytes[1:6].hex().upper() + + # Length of DLLP - 1 byte + dllp_length = atr_bytes[6] + atr["DLLP_LENGTH"] = dllp_length + + # DLLP - Variable length (Decode using struct) + dllp = atr_bytes[7 : 7 + dllp_length] + atr["DLLP"] = dllp.hex().upper() + if dllp_length >= 4: + atr["BWT"], atr["IFSC"] = struct.unpack(">HH", dllp[:4]) + + # PLID - 1 byte + atr["PLID"] = atr_bytes[7 + dllp_length] + # Length of PLP - 1 byte + plp_length = atr_bytes[8 + dllp_length] + atr["PLP_LENGTH"] = plp_length + + # PLP - Variable length (Decode using struct) + plp = atr_bytes[9 + dllp_length : 9 + dllp_length + plp_length] + atr["PLP"] = plp.hex().upper() + if plp_length >= 2: + atr["MCF"] = struct.unpack(">H", plp[:2])[0] + if plp_length >= 3: + atr["CONFIGURATION"] = plp[2] + if plp_length >= 4: + atr["MPOT"] = plp[3] + if plp_length >= 6: + atr["SEGT"], atr["WUT"] = struct.unpack(">HH", plp[4:8]) + + # Length of HB - 1 byte + hb_length = atr_bytes[9 + dllp_length + plp_length] + atr["HB_LENGTH"] = hb_length + # HB - Variable length + hb = atr_bytes[10 + dllp_length + plp_length : 10 + dllp_length + plp_length + hb_length] + atr["HB"] = hb.hex().upper() + return atr + + def _dump_atrs(self, atr): + logging.info(f"PVER (Protocol Version): {atr['PVER']}") + logging.info(f"VID (Vendor ID): {atr['VID']}") + logging.info(f"Length of DLLP: {atr['DLLP_LENGTH']}") + + if "DLLP" in atr: + logging.info(f"DLLP: {atr['DLLP']}") + + if "BWT" in atr and "IFSC" in atr: + logging.info(f"BWT (Block Waiting Time): {atr['BWT']} ms") + logging.info(f"IFSC (Maximum Information Field Size): {atr['IFSC']} bytes") + + logging.info(f"PLID (Physical Layer ID): {atr['PLID']}") + logging.info(f"Length of PLP: {atr['PLP_LENGTH']}") + + if "PLP" in atr: + logging.info(f"PLP: {atr['PLP']}") + + if "MCF" in atr: + logging.info(f"MCF (Max I2C Clock Frequency): {atr['MCF']} kHz") + + if "CONFIGURATION" in atr: + logging.info(f"Configuration: {atr['CONFIGURATION']:#04x}") + + if "MPOT" in atr: + logging.info(f"MPOT (Minimum Polling Time): {atr['MPOT']} ms") + + if "SEGT" in atr and "WUT" in atr: + logging.info(f"SEGT (Secure Element Guard Time): {atr['SEGT']} µs") + logging.info(f"WUT (Wake-Up Time): {atr['WUT']} µs") + + logging.info(f"Length of HB (Historical Bytes): {atr['HB_LENGTH']}") + if "HB" in atr: + logging.info(f"HB (Historical Bytes): {atr['HB']}") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/iso7816.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/iso7816.pyi new file mode 100644 index 000000000..b907567a9 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/iso7816.pyi @@ -0,0 +1,62 @@ +from _typeshed import Incomplete +from micropython import const as const + +_NAD_OFFSET: int +_PCB_OFFSET: int +_LEN_OFFSET: int +_INF_OFFSET: int +_I_BLOCK: int +_I_BLOCK_N: int +_I_BLOCK_M: int +_S_BLOCK: int +_S_BLOCK_REQ: int +_R_BLOCK: int +_R_BLOCK_N: int +_R_BLOCK_ERR: int +_RESYNC_REQ: int +_IFS_REQ: int +_ABORT_REQ: int +_WTX_REQ: int +_END_SESSION_REQ: int +_CHIP_RESET_REQ: int +_GET_ATR_REQ: int +_SOFT_RESET_REQ: int +_CLA_ISO7816: int +_INS_GP_SELECT: int +_STATE_IBLK: int +_STATE_SBLK: int +_STATE_SEND: int +_STATE_RECV: int +_STATE_WAIT: int +_STATE_WWTX: int +_STATE_DONE: int + +def log_enabled(level): ... + +class SmartCard: + seq: int + bus: Incomplete + sad: Incomplete + dad: Incomplete + aid: Incomplete + atr: Incomplete + w_buf: Incomplete + r_buf: Incomplete + s_buf: Incomplete + apdu_buf: Incomplete + block_name: Incomplete + state_name: Incomplete + apdu_status: Incomplete + def __init__(self, bus, nad, aid) -> None: ... + def _block_type(self, pcb): ... + def _block_size(self, buf): ... + def _block_crc16(self, prologue, data, poly: int = 33800, crc: int = 65535): ... + def _block_write(self, buf, delay: int = 0) -> None: ... + def _block_print(self, txrx, *args) -> None: ... + def _block_new(self, buf, btype, **kwargs): ... + def _send_block(self, btype, arg, retry: int = 25, backoff: float = 1.2): ... + def send_apdu(self, cla, ins, p1, p2, data=None, le: int = 0): ... + def reset(self) -> None: ... + def resync(self) -> None: ... + def _parse_atrs(self, atr_bytes): ... + def _dump_atrs(self, atr) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/se05x.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/se05x.py new file mode 100644 index 000000000..0409a5eb1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/se05x.py @@ -0,0 +1,250 @@ +# This file is part of the se05x package. +# Copyright (c) 2024 Arduino SA +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# NXP SE05x EdgeLock device driver. + +import struct +import logging +from time import sleep_ms +from machine import I2C +from machine import Pin +from .iso7816 import SmartCard +from micropython import const + +_RESULT_OK = 1 +_APPLET_NAD = 0x5A +_APPLET_AID = const(b"\xa0\x00\x00\x03\x96\x54\x53\x00\x00\x00\x01\x03\x00\x00\x00\x00") +_CLA_KSE05X = 0x80 + +_INS_WRITE = 0x01 +_INS_READ = 0x02 +_INS_CRYPTO = 0x03 +_INS_MGMT = 0x04 +_INS_PROCESS = 0x05 +_INS_IMPORT_EXTERNAL = 0x06 +_INS_TRANSIENT = 0x80 +_INS_AUTH_OBJECT = 0x40 +_INS_ATTEST = 0x20 + +_P1_DEFAULT = 0x00 +_P1_EC = 0x01 +_P1_AES = 0x03 +_P1_DES = 0x04 +_P1_HMAC = 0x05 +_P1_BINARY = 0x06 +_P1_USERID = 0x07 +_P1_CURVE = 0x0B +_P1_SIGNATURE = 0x0C +_P1_MAC = 0x0D +_P1_CIPHER = 0x0E +_P1_KEY_PRIVATE = 0x40 +_P1_KEY_PUBLIC = 0x20 + +_P2_DEFAULT = 0x00 +_P2_GENERATE = 0x03 +_P2_CREATE = 0x04 +_P2_SIZE = 0x07 +_P2_SIGN = 0x09 +_P2_VERIFY = 0x0A +_P2_SESSION_CREATE = 0x1B +_P2_SESSION_CLOSE = 0x1C +_P2_VERSION = 0x20 +_P2_LIST = 0x25 +_P2_EXIST = 0x27 +_P2_DELETE_OBJECT = 0x28 +_P2_SESSION_USERID = 0x2C +_P2_DH = 0x0F +_P2_ENCRYPT_ONESHOT = 0x37 +_P2_DECRYPT_ONESHOT = 0x38 +_P2_SCP = 0x52 +_P2_ONESHOT = 0x0E + +_TLV_TAG1 = 0x41 +_TLV_TAG2 = 0x42 +_TLV_TAG3 = 0x43 +_TLV_TAG4 = 0x44 +_TLV_TAG5 = 0x45 +_TLV_TAG6 = 0x46 +_TLV_TAG7 = 0x47 +_TLV_TAG8 = 0x48 +_TLV_TAG9 = 0x49 +_TLV_TAG10 = 0x4A +_TLV_TAG11 = 0x4B +_TLV_TAG_SESSION_ID = 0x10 +_TLV_TAG_POLICY = 0x11 +_TLV_TAG_MAX_ATTEMPTS = 0x12 +_TLV_TAG_IMPORT_AUTH_DATA = 0x13 +_TLV_TAG_IMPORT_AUTH_KEY_ID = 0x14 +_TLV_TAG_POLICY_CHECK = 0x15 + +_SIG_ECDSA_SHA_1 = 0x11 +_SIG_ECDSA_SHA_224 = 0x25 +_SIG_ECDSA_SHA_256 = 0x21 +_SIG_ECDSA_SHA_384 = 0x22 +_SIG_ECDSA_SHA_512 = 0x26 + + +class I2CBus: + def __init__(self, addr, freq): + self.addr = addr + self.bus = None + # Scan the first 3 I2C buses + for i in range(3): + try: + bus = I2C(i, freq=freq) + if self.addr in bus.scan(): + logging.info(f"SE05x detected on bus: {i} addr: 0x{addr:02X}") + self.bus = bus + break + except Exception: + pass + if self.bus is None: + raise RuntimeError("Failed to detect SE05x on I2C bus") + + def read(self, buf): + self.bus.readfrom_into(self.addr, buf) + return buf + + def write(self, buf): + self.bus.writeto(self.addr, buf) + + +class SE05X: + def __init__(self, addr=0x48, freq=400_000, rst=Pin("SE05X_EN", Pin.OUT_PP, Pin.PULL_UP)): + self.rst = rst + self.scard = None + self.reset() + self.bus = I2CBus(addr, freq) + self.scard = SmartCard(self.bus, _APPLET_NAD, _APPLET_AID) + self.scard.reset() + self.ecdsa_algo = { + 160: _SIG_ECDSA_SHA_1, + 224: _SIG_ECDSA_SHA_224, + 256: _SIG_ECDSA_SHA_256, + 384: _SIG_ECDSA_SHA_384, + 512: _SIG_ECDSA_SHA_512, + } + self.tlv_offs = 0 + self.tlv_buf = memoryview(bytearray(254)) + + def _tlv_pack(self, fmt, *args): + struct.pack_into(fmt, self.tlv_buf, self.tlv_offs, *args) + self.tlv_offs += struct.calcsize(fmt) + + def _tlv_flush(self): + mv = self.tlv_buf[0 : self.tlv_offs] + self.tlv_offs = 0 + return mv + + def _ecdsa_algo(self, hash_size): + if hash_size * 8 not in self.ecdsa_algo: + raise ValueError("Invalid SHA digest size") + return self.ecdsa_algo[hash_size * 8] + + def reset(self, reset_card=True): + self.rst.low() + sleep_ms(10) + self.rst.high() + sleep_ms(10) + if self.scard is not None: + self.scard.reset() + + def version(self): + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_MGMT, _P1_DEFAULT, _P2_VERSION) + major, minor, patch = struct.unpack(">BBB", resp) + return major, minor, patch + + def read(self, obj_id, size=0): + if not self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} doesn't exist.") + if size == 0: + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_READ, _P1_DEFAULT, _P2_DEFAULT, self._tlv_flush()) + return bytes(resp) + offset = 0 + buf = bytearray() + maxblk = 254 - struct.calcsize("BBIBBHBBH") + while size: + bsize = min(size, maxblk) + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self._tlv_pack(">BBH", _TLV_TAG2, 0x2, offset) + self._tlv_pack(">BBH", _TLV_TAG3, 0x2, bsize) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_READ, _P1_DEFAULT, _P2_DEFAULT, self._tlv_flush()) + buf.extend(resp) + offset += bsize + size -= bsize + return bytes(buf) + + def write(self, obj_id, obj_type, **kwargs): + if self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} already exists.") + + ins = _INS_WRITE | kwargs.get("ins_flags", 0) + if obj_type == _P1_EC: + p1 = _P1_EC + key = kwargs.get("key", (None, None)) + curve_id = kwargs.get("curve", 0x3) + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self._tlv_pack(">BBB", _TLV_TAG2, 0x1, curve_id) + if key[0] is not None: + p1 |= _P1_KEY_PRIVATE + self._tlv_pack(f"BB{len(key[0])}s", _TLV_TAG3, len(key[0]), key[0]) + if key[1] is not None: + p1 |= _P1_KEY_PUBLIC + self._tlv_pack(f"BB{len(key[1])}s", _TLV_TAG4, len(key[1]), key[1]) + if key[0] is None and key[1] is None: + p1 |= _P1_KEY_PRIVATE | _P1_KEY_PUBLIC + self.scard.send_apdu(_CLA_KSE05X, ins, p1, _P2_DEFAULT, self._tlv_flush()) + elif obj_type == _P1_BINARY: + offset = 0 + binary = kwargs["binary"] + maxblk = 254 - struct.calcsize("BBIBBHBBHBBH") + remain = len(binary) + while remain: + bsize = min(remain, maxblk) + data = binary[offset : offset + bsize] + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self._tlv_pack(">BBH", _TLV_TAG2, 0x2, offset) + if offset == 0: + self._tlv_pack(">BBH", _TLV_TAG3, 0x2, remain) + self._tlv_pack(f">BBH{bsize}s", _TLV_TAG4, 0x82, bsize, data) + self.scard.send_apdu(_CLA_KSE05X, ins, _P1_BINARY, _P2_DEFAULT, self._tlv_flush()) + offset += bsize + remain -= bsize + + def delete(self, obj_id): + if not self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} doesn't exist.") + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self.scard.send_apdu(_CLA_KSE05X, _INS_MGMT, _P1_DEFAULT, _P2_DELETE_OBJECT, self._tlv_flush()) + + def exists(self, obj_id): + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_MGMT, _P1_DEFAULT, _P2_EXIST, self._tlv_flush()) + return resp[0] == _RESULT_OK + + def sign(self, obj_id, data): + if not self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} doesn't exist.") + hash_size = len(data) + hash_algo = self._ecdsa_algo(hash_size) + self._tlv_pack(">BBIBBB", _TLV_TAG1, 0x4, obj_id, _TLV_TAG2, 0x1, hash_algo) + self._tlv_pack(f"BB{hash_size}s", _TLV_TAG3, hash_size, data) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_CRYPTO, _P1_SIGNATURE, _P2_SIGN, self._tlv_flush()) + return bytes(resp) + + def verify(self, obj_id, data, sign): + if not self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} doesn't exist.") + hash_size = len(data) + sign_size = len(sign) + hash_algo = self._ecdsa_algo(hash_size) + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self._tlv_pack(">BBB", _TLV_TAG2, 0x1, hash_algo) + self._tlv_pack(f"BB{hash_size}s", _TLV_TAG3, hash_size, data) + self._tlv_pack(f"BB{sign_size}s", _TLV_TAG5, sign_size, sign) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_CRYPTO, _P1_SIGNATURE, _P2_VERIFY, self._tlv_flush()) + return resp[0] == _RESULT_OK diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/se05x.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/se05x.pyi new file mode 100644 index 000000000..db8f302f5 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/se05x/se05x.pyi @@ -0,0 +1,96 @@ +from .iso7816 import SmartCard as SmartCard +from _typeshed import Incomplete + +_RESULT_OK: int +_APPLET_NAD: int +_APPLET_AID: Incomplete +_CLA_KSE05X: int +_INS_WRITE: int +_INS_READ: int +_INS_CRYPTO: int +_INS_MGMT: int +_INS_PROCESS: int +_INS_IMPORT_EXTERNAL: int +_INS_TRANSIENT: int +_INS_AUTH_OBJECT: int +_INS_ATTEST: int +_P1_DEFAULT: int +_P1_EC: int +_P1_AES: int +_P1_DES: int +_P1_HMAC: int +_P1_BINARY: int +_P1_USERID: int +_P1_CURVE: int +_P1_SIGNATURE: int +_P1_MAC: int +_P1_CIPHER: int +_P1_KEY_PRIVATE: int +_P1_KEY_PUBLIC: int +_P2_DEFAULT: int +_P2_GENERATE: int +_P2_CREATE: int +_P2_SIZE: int +_P2_SIGN: int +_P2_VERIFY: int +_P2_SESSION_CREATE: int +_P2_SESSION_CLOSE: int +_P2_VERSION: int +_P2_LIST: int +_P2_EXIST: int +_P2_DELETE_OBJECT: int +_P2_SESSION_USERID: int +_P2_DH: int +_P2_ENCRYPT_ONESHOT: int +_P2_DECRYPT_ONESHOT: int +_P2_SCP: int +_P2_ONESHOT: int +_TLV_TAG1: int +_TLV_TAG2: int +_TLV_TAG3: int +_TLV_TAG4: int +_TLV_TAG5: int +_TLV_TAG6: int +_TLV_TAG7: int +_TLV_TAG8: int +_TLV_TAG9: int +_TLV_TAG10: int +_TLV_TAG11: int +_TLV_TAG_SESSION_ID: int +_TLV_TAG_POLICY: int +_TLV_TAG_MAX_ATTEMPTS: int +_TLV_TAG_IMPORT_AUTH_DATA: int +_TLV_TAG_IMPORT_AUTH_KEY_ID: int +_TLV_TAG_POLICY_CHECK: int +_SIG_ECDSA_SHA_1: int +_SIG_ECDSA_SHA_224: int +_SIG_ECDSA_SHA_256: int +_SIG_ECDSA_SHA_384: int +_SIG_ECDSA_SHA_512: int + +class I2CBus: + addr: Incomplete + bus: Incomplete + def __init__(self, addr, freq) -> None: ... + def read(self, buf): ... + def write(self, buf) -> None: ... + +class SE05X: + rst: Incomplete + scard: Incomplete + bus: Incomplete + ecdsa_algo: Incomplete + tlv_offs: int + tlv_buf: Incomplete + def __init__(self, addr: int = 72, freq: int = 400000, rst=...) -> None: ... + def _tlv_pack(self, fmt, *args) -> None: ... + def _tlv_flush(self): ... + def _ecdsa_algo(self, hash_size): ... + def reset(self, reset_card: bool = True) -> None: ... + def version(self): ... + def read(self, obj_id, size: int = 0): ... + def write(self, obj_id, obj_type, **kwargs) -> None: ... + def delete(self, obj_id) -> None: ... + def exists(self, obj_id): ... + def sign(self, obj_id, data): ... + def verify(self, obj_id, data, sign): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/__init__.py new file mode 100644 index 000000000..908375fdb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/__init__.py @@ -0,0 +1,29 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from .senml_base import SenmlBase +from .senml_pack import SenmlPack +from .senml_record import SenmlRecord +from .senml_unit import SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/__init__.pyi new file mode 100644 index 000000000..c72285dc4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/__init__.pyi @@ -0,0 +1,4 @@ +from .senml_base import SenmlBase as SenmlBase +from .senml_pack import SenmlPack as SenmlPack +from .senml_record import SenmlRecord as SenmlRecord +from .senml_unit import SenmlUnits as SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_base.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_base.py new file mode 100644 index 000000000..b277c9477 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_base.py @@ -0,0 +1,30 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +class SenmlBase(object): + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_base.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_base.pyi new file mode 100644 index 000000000..240f185ce --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_base.pyi @@ -0,0 +1,4 @@ +class SenmlBase: + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_pack.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_pack.py new file mode 100644 index 000000000..5a0554467 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_pack.py @@ -0,0 +1,358 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from senml.senml_record import SenmlRecord +from senml.senml_base import SenmlBase +import json +import cbor2 + + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + def __init__(self, list): + self._list = list + self._index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self._index < len(self._list): + res = self._list[self._index] + self._index += 1 + return res + else: + raise StopIteration + + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings = { + "bn": "bn", + "bt": "bt", + "bu": "bu", + "bv": "bv", + "bs": "bs", + "n": "n", + "u": "u", + "v": "v", + "vs": "vs", + "vb": "vb", + "vd": "vd", + "s": "s", + "t": "t", + "ut": "ut", + } + + def __init__(self, name, callback=None): + """ + initialize the object + :param name: {string} the name of the pack + """ + self._data = [] + self.name = name + self._base_value = None + self._base_time = None + self._base_sum = None + self.base_unit = None + self._parent = None # a pack can also be the child of another pack. + self.actuate = callback # actuate callback function + + def __iter__(self): + return SenmlPackIterator(self._data) + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + return self._base_value + + @base_value.setter + def base_value(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_value") + self._base_value = value + + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + return self._base_sum + + @base_sum.setter + def base_sum(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_sum") + self._base_sum = value + + @property + def base_time(self): + return self._base_time + + @base_time.setter + def base_time(self, value): + self._check_value_type(value, "base_time") + self._base_time = value + + def _check_value_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + def from_json(self, data): + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + records = json.loads(data) # load the raw senml data + self._process_incomming_data(records, SenmlPack.json_mappings) + + def _process_incomming_data(self, records, naming_map): + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + cur_pack_el = self + new_pack = False + for item in records: + if naming_map["bn"] in item: # ref to a pack element, either this or a child pack. + if item[naming_map["bn"]] != self.name: + pack_el = [x for x in self._data if x.name == item[naming_map["bn"]]] + else: + pack_el = [self] + if len(pack_el) > 0: + cur_pack_el = pack_el[0] + new_pack = False + else: + device = SenmlPack(item[naming_map["bn"]]) + self._data.append(device) + cur_pack_el = device + new_pack = True + + if ( + naming_map["bv"] in item + ): # need to copy the base value assigned to the pack element so we can do proper conversion for actuators. + cur_pack_el.base_value = item[naming_map["bv"]] + + rec_el = [x for x in cur_pack_el._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + else: + rec_el = [x for x in self._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + + def do_actuate(self, raw, naming_map, device=None): + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + rec = SenmlRecord(raw[naming_map["n"]]) + if device: + device.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=device) + else: + self.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=None) + + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + converted = [] + self._build_rec_dict(SenmlPack.json_mappings, converted) + return json.dumps(converted) + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + internalList = [] + for item in self._data: + item._build_rec_dict(naming_map, internalList) + if len(internalList) > 0: + first_rec = internalList[0] + else: + first_rec = {} + internalList.append(first_rec) + + if self.name: + first_rec[naming_map["bn"]] = self.name + if self.base_value: + first_rec[naming_map["bv"]] = self.base_value + if self.base_unit: + first_rec[naming_map["bu"]] = self.base_unit + if self.base_sum: + first_rec[naming_map["bs"]] = self.base_sum + if self.base_time: + first_rec[naming_map["bt"]] = self.base_time + appendTo.extend(internalList) + + def from_cbor(self, data): + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + records = cbor2.loads(data) # load the raw senml data + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + self._process_incomming_data(records, naming_map) + + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + converted = [] + self._build_rec_dict(naming_map, converted) + return cbor2.dumps(converted) + + def add(self, item): + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if item._parent is not None: + raise Exception("item is already part of a pack") + + self._data.append(item) + item._parent = self + + def remove(self, item): + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if not item._parent == self: + raise Exception("item is not part of this pack") + + self._data.remove(item) + item._parent = None + + def clear(self): + """ + clear the list of the pack + :return: None + """ + for item in self._data: + item._parent = None + self._data = [] diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_pack.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_pack.pyi new file mode 100644 index 000000000..57a0cf547 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_pack.pyi @@ -0,0 +1,143 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase +from senml.senml_record import SenmlRecord as SenmlRecord + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + _list: Incomplete + _index: int + def __init__(self, list) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings: Incomplete + _data: Incomplete + name: Incomplete + _base_value: Incomplete + _base_time: Incomplete + _base_sum: Incomplete + base_unit: Incomplete + _parent: Incomplete + actuate: Incomplete + def __init__(self, name, callback=None) -> None: + """ + initialize the object + :param name: {string} the name of the pack + """ + def __iter__(self): ... + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + @base_value.setter + def base_value(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + @base_sum.setter + def base_sum(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_time(self): ... + @base_time.setter + def base_time(self, value) -> None: ... + def _check_value_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def from_json(self, data) -> None: + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + def _process_incomming_data(self, records, naming_map) -> None: + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + def do_actuate(self, raw, naming_map, device=None) -> None: + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + def from_cbor(self, data) -> None: + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + def add(self, item) -> None: + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + def remove(self, item) -> None: + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + def clear(self) -> None: + """ + clear the list of the pack + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_record.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_record.py new file mode 100644 index 000000000..b5b07b0bc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_record.py @@ -0,0 +1,240 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import binascii +from senml.senml_base import SenmlBase + + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + def __init__(self, name, **kwargs): + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + self.__parent = None # using double __ cause it's a field for an internal property + self._unit = None # declare and init internal fields + self._value = None + self._time = None + self._sum = None + self._update_time = None + + self._parent = None # internal reference to the parent object + self.name = name + self.unit = kwargs.get("unit", None) + self.value = kwargs.get("value", None) + self.time = kwargs.get("time", None) + self.sum = kwargs.get("sum", None) + self.update_time = kwargs.get("update_time", None) + self.actuate = kwargs.get("callback", None) # actuate callback function + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + def _check_value_type(self, value): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not ( + isinstance(value, bool) + or isinstance(value, int) + or isinstance(value, float) + or isinstance(value, bytearray) + or isinstance(value, str) + ): + raise Exception("invalid type for value, only numbers, strings, boolean and byte arrays allowed") + + def _check_number_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + @property + def value(self): + """get the value currently assigned to the object""" + return self._value + + @value.setter + def value(self, value): + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + self._check_value_type(value) + self._value = value + + @property + def time(self): + return self._time + + @time.setter + def time(self, value): + self._check_number_type(value, "time") + self._time = value + + @property + def update_time(self): + return self._update_time + + @update_time.setter + def update_time(self, value): + self._check_number_type(value, "update_time") + self._update_time = value + + @property + def sum(self): + return self._sum + + @sum.setter + def sum(self, value): + self._check_number_type(value, "sum") + self._sum = value + + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + return self.__parent + + @_parent.setter + def _parent(self, value): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + self.__parent = value + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + result = {} + + if self.name: + result[naming_map["n"]] = self.name + + if self._sum: + if self._parent and self._parent.base_sum: + result[naming_map["s"]] = self._sum - self._parent.base_sum + else: + result[naming_map["s"]] = self._sum + elif isinstance(self._value, bool): + result[naming_map["vb"]] = self._value + elif isinstance(self._value, int) or isinstance(self._value, float): + if self._parent and self._parent.base_value: + result[naming_map["v"]] = self._value - self._parent.base_value + else: + result[naming_map["v"]] = self._value + elif isinstance(self._value, str): + result[naming_map["vs"]] = self._value + elif isinstance(self._value, bytearray): + if naming_map["vd"] == "vd": # neeed to make a distinction between json (needs base64) and cbor (needs binary) + result[naming_map["vd"]] = binascii.b2a_base64(self._value, newline=False).decode("utf8") + else: + result[naming_map["vd"]] = self._value + else: + raise Exception("sum or value of type bootl, number, string or byte-array is required") + + if self._time: + if self._parent and self._parent.base_time: + result[naming_map["t"]] = self._time - self._parent.base_time + else: + result[naming_map["t"]] = self._time + + if self.unit: + result[naming_map["u"]] = self.unit + + if self._update_time: + if self._parent and self._parent.base_time: + result[naming_map["ut"]] = self._update_time - self._parent.base_time + else: + result[naming_map["ut"]] = self._update_time + + appendTo.append(result) + + def _from_raw(self, raw, naming_map): + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + if naming_map["v"] in raw: + val = raw[naming_map["v"]] + if self._parent and self._parent.base_value: + val += self._parent.base_value + elif naming_map["vs"] in raw: + val = raw[naming_map["vs"]] + elif naming_map["vb"] in raw: + val = raw[naming_map["vb"]] + elif naming_map["vd"] in raw: + val = binascii.a2b_base64(raw[naming_map["vb"]]) + else: + val = None + self.value = val + + def do_actuate(self, raw, naming_map): + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ + self._from_raw(raw, naming_map) + if self.actuate: + self.actuate(self) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_record.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_record.pyi new file mode 100644 index 000000000..61c0c7c05 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_record.pyi @@ -0,0 +1,104 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + __parent: Incomplete + _unit: Incomplete + _value: Incomplete + _time: Incomplete + _sum: Incomplete + _update_time: Incomplete + name: Incomplete + unit: Incomplete + actuate: Incomplete + def __init__(self, name, **kwargs) -> None: + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + def _check_value_type(self, value) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def _check_number_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + @property + def value(self): + """get the value currently assigned to the object""" + @value.setter + def value(self, value) -> None: + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + @property + def time(self): ... + @time.setter + def time(self, value) -> None: ... + @property + def update_time(self): ... + @update_time.setter + def update_time(self, value) -> None: ... + @property + def sum(self): ... + @sum.setter + def sum(self, value) -> None: ... + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + @_parent.setter + def _parent(self, value) -> None: + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + def _from_raw(self, raw, naming_map) -> None: + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + def do_actuate(self, raw, naming_map) -> None: + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_unit.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_unit.py new file mode 100644 index 000000000..bf7753c4d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_unit.py @@ -0,0 +1,89 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +def enum(**enums): + return type("Enum", (), enums) + + +SenmlUnits = enum( + SENML_UNIT_METER="m", + SENML_UNIT_KILOGRAM="kg", + SENML_UNIT_GRAM="g", + SENML_UNIT_SECOND="s", + SENML_UNIT_AMPERE="A", + SENML_UNIT_KELVIN="K", + SENML_UNIT_CANDELA="cd", + SENML_UNIT_MOLE="mol", + SENML_UNIT_HERTZ="Hz", + SENML_UNIT_RADIAN="rad", + SENML_UNIT_STERADIAN="sr", + SENML_UNIT_NEWTON="N", + SENML_UNIT_PASCAL="Pa", + SENML_UNIT_JOULE="J", + SENML_UNIT_WATT="W", + SENML_UNIT_COULOMB="C", + SENML_UNIT_VOLT="V", + SENML_UNIT_FARAD="F", + SENML_UNIT_OHM="Ohm", + SENML_UNIT_SIEMENS="S", + SENML_UNIT_WEBER="Wb", + SENML_UNIT_TESLA="T", + SENML_UNIT_HENRY="H", + SENML_UNIT_DEGREES_CELSIUS="Cel", + SENML_UNIT_LUMEN="lm", + SENML_UNIT_LUX="lx", + SENML_UNIT_BECQUEREL="Bq", + SENML_UNIT_GRAY="Gy", + SENML_UNIT_SIEVERT="Sv", + SENML_UNIT_KATAL="kat", + SENML_UNIT_SQUARE_METER="m2", + SENML_UNIT_CUBIC_METER="m3", + SENML_UNIT_LITER="l", + SENML_UNIT_VELOCITY="m/s", + SENML_UNIT_ACCELERATION="m/s2", + SENML_UNIT_CUBIC_METER_PER_SECOND="m3/s", + SENML_UNIT_LITER_PER_SECOND="l/s", + SENML_UNIT_WATT_PER_SQUARE_METER="W/m2", + SENML_UNIT_CANDELA_PER_SQUARE_METER="cd/m2", + SENML_UNIT_BIT="bit", + SENML_UNIT_BIT_PER_SECOND="bit/s", + SENML_UNIT_DEGREES_LATITUDE="lat", + SENML_UNIT_DEGREES_LONGITUDE="lon", + SENML_UNIT_PH="pH", + SENML_UNIT_DECIBEL="db", + SENML_UNIT_DECIBEL_RELATIVE_TO_1_W="dBW", + SENML_UNIT_BEL="Bspl", + SENML_UNIT_COUNTER="count", + SENML_UNIT_RATIO="//", + SENML_UNIT_RELATIVE_HUMIDITY="%RH", + SENML_UNIT_PERCENTAGE_REMAINING_BATTERY_LEVEL="%EL", + SENML_UNIT_SECONDS_REMAINING_BATTERY_LEVEL="EL", + SENML_UNIT_EVENT_RATE_PER_SECOND="1/s", + SENML_UNIT_EVENT_RATE_PER_MINUTE="1/min", + SENML_UNIT_BPM="beat/min", + SENML_UNIT_BEATS="beats", + SENML_UNIT_SIEMENS_PER_METER="S/m", +) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_unit.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_unit.pyi new file mode 100644 index 000000000..6b3e7ae68 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/senml/senml_unit.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +def enum(**enums): ... + +SenmlUnits: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/time.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/time.py new file mode 100644 index 000000000..f79ab8a3b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/time.py @@ -0,0 +1,79 @@ +from utime import * +from micropython import const + +_TS_YEAR = 0 +_TS_MON = 1 +_TS_MDAY = 2 +_TS_HOUR = 3 +_TS_MIN = 4 +_TS_SEC = 5 +_TS_WDAY = 6 +_TS_YDAY = 7 +_TS_ISDST = 8 + +_WDAY = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") +_MDAY = const( + ( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ) +) + + +def strftime(datefmt, ts): + from io import StringIO + + fmtsp = False + ftime = StringIO() + for k in datefmt: + if fmtsp: + if k == "a": + ftime.write(_WDAY[ts[_TS_WDAY]][0:3]) + elif k == "A": + ftime.write(_WDAY[ts[_TS_WDAY]]) + elif k == "b": + ftime.write(_MDAY[ts[_TS_MON] - 1][0:3]) + elif k == "B": + ftime.write(_MDAY[ts[_TS_MON] - 1]) + elif k == "d": + ftime.write("%02d" % ts[_TS_MDAY]) + elif k == "H": + ftime.write("%02d" % ts[_TS_HOUR]) + elif k == "I": + ftime.write("%02d" % (ts[_TS_HOUR] % 12)) + elif k == "j": + ftime.write("%03d" % ts[_TS_YDAY]) + elif k == "m": + ftime.write("%02d" % ts[_TS_MON]) + elif k == "M": + ftime.write("%02d" % ts[_TS_MIN]) + elif k == "P": + ftime.write("AM" if ts[_TS_HOUR] < 12 else "PM") + elif k == "S": + ftime.write("%02d" % ts[_TS_SEC]) + elif k == "w": + ftime.write(str(ts[_TS_WDAY])) + elif k == "y": + ftime.write("%02d" % (ts[_TS_YEAR] % 100)) + elif k == "Y": + ftime.write(str(ts[_TS_YEAR])) + else: + ftime.write(k) + fmtsp = False + elif k == "%": + fmtsp = True + else: + ftime.write(k) + val = ftime.getvalue() + ftime.close() + return val diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/time.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/time.pyi new file mode 100644 index 000000000..26b0e4b08 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/time.pyi @@ -0,0 +1,59 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. +""" + +from __future__ import annotations +from utime import * +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TS_YEAR: int +_TS_MON: int +_TS_MDAY: int +_TS_HOUR: int +_TS_MIN: int +_TS_SEC: int +_TS_WDAY: int +_TS_YDAY: int +_TS_ISDST: int +_WDAY: Incomplete +_MDAY: Incomplete +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def strftime(datefmt, ts): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_NICLA_VISION/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/central.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/client.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/core.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/device.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/security.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/server.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/__init__.py new file mode 100644 index 000000000..80790f0da --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/__init__.py @@ -0,0 +1,32 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from ._decoder import CBORDecoder +from ._decoder import load +from ._decoder import loads + +from ._encoder import CBOREncoder +from ._encoder import dump +from ._encoder import dumps diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/__init__.pyi new file mode 100644 index 000000000..0ef59d019 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/__init__.pyi @@ -0,0 +1,2 @@ +from ._decoder import CBORDecoder as CBORDecoder, load as load, loads as loads +from ._encoder import CBOREncoder as CBOREncoder, dump as dump, dumps as dumps diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_decoder.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_decoder.py new file mode 100644 index 000000000..8434aec26 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_decoder.py @@ -0,0 +1,254 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + + +break_marker = object() + + +class CBORSimpleValue(object): + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + def __init__(self, value): + if value < 0 or value > 255: + raise TypeError("simple value too big") + self.value = value + + def __eq__(self, other): + if isinstance(other, CBORSimpleValue): + return self.value == other.value + elif isinstance(other, int): + return self.value == other + return NotImplemented + + def __repr__(self): + return "CBORSimpleValue({self.value})".format(self=self) + + +def decode_uint(decoder, subtype, allow_indefinite=False): + # Major tag 0 + if subtype < 24: + return subtype + elif subtype == 24: + return struct.unpack(">B", decoder.read(1))[0] + elif subtype == 25: + return struct.unpack(">H", decoder.read(2))[0] + elif subtype == 26: + return struct.unpack(">L", decoder.read(4))[0] + elif subtype == 27: + return struct.unpack(">Q", decoder.read(8))[0] + elif subtype == 31 and allow_indefinite: + return None + else: + raise CBORDecodeError("unknown unsigned integer subtype 0x%x" % subtype) + + +def decode_negint(decoder, subtype): + # Major tag 1 + uint = decode_uint(decoder, subtype) + return -uint - 1 + + +def decode_bytestring(decoder, subtype): + # Major tag 2 + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + buf = bytearray() + while True: + initial_byte = decoder.read(1)[0] + if initial_byte == 255: + return buf + else: + length = decode_uint(decoder, initial_byte & 31) + value = decoder.read(length) + buf.extend(value) + else: + return decoder.read(length) + + +def decode_string(decoder, subtype): + # Major tag 3 + return decode_bytestring(decoder, subtype).decode("utf-8") + + +def decode_array(decoder, subtype): + # Major tag 4 + items = [] + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + value = decoder.decode() + if value is break_marker: + break + else: + items.append(value) + else: + for _ in range(length): + item = decoder.decode() + items.append(item) + return items + + +def decode_map(decoder, subtype): + # Major tag 5 + dictionary = {} + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + key = decoder.decode() + if key is break_marker: + break + else: + value = decoder.decode() + dictionary[key] = value + else: + for _ in range(length): + key = decoder.decode() + value = decoder.decode() + dictionary[key] = value + + return dictionary + + +def decode_special(decoder, subtype): + # Simple value + if subtype < 20: + return CBORSimpleValue(subtype) + + # Major tag 7 + return special_decoders[subtype](decoder) + + +def decode_simple_value(decoder): + return CBORSimpleValue(struct.unpack(">B", decoder.read(1))[0]) + + +def decode_float16(decoder): + decoder.read(2) + raise NotImplementedError # no float16 unpack function + + +def decode_float32(decoder): + return struct.unpack(">f", decoder.read(4))[0] + + +def decode_float64(decoder): + return struct.unpack(">d", decoder.read(8))[0] + + +major_decoders = { + 0: decode_uint, + 1: decode_negint, + 2: decode_bytestring, + 3: decode_string, + 4: decode_array, + 5: decode_map, + 7: decode_special, +} + +special_decoders = { + 20: lambda self: False, + 21: lambda self: True, + 22: lambda self: None, + # 23 is undefined + 24: decode_simple_value, + 25: decode_float16, + 26: decode_float32, + 27: decode_float64, + 31: lambda self: break_marker, +} + + +class CBORDecoder(object): + """ + Deserializes a CBOR encoded byte stream. + """ + + def __init__(self, fp): + self.fp = fp + + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + data = self.fp.read(amount) + if len(data) < amount: + raise CBORDecodeError("premature end of stream (expected to read {} bytes, got {} instead)".format(amount, len(data))) + + return data + + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + try: + initial_byte = self.fp.read(1)[0] + major_type = initial_byte >> 5 + subtype = initial_byte & 31 + except Exception as e: + raise CBORDecodeError("error reading major type at index {}: {}".format(self.fp.tell(), e)) + + decoder = major_decoders[major_type] + try: + return decoder(self, subtype) + except CBORDecodeError: + raise + except Exception as e: + raise CBORDecodeError("error decoding value {}".format(e)) # tell doesn't work on micropython at the moment + + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + fp = io.BytesIO(payload) + return CBORDecoder(fp, **kwargs).decode() + + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + return CBORDecoder(fp, **kwargs).decode() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_decoder.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_decoder.pyi new file mode 100644 index 000000000..d4daffe85 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_decoder.pyi @@ -0,0 +1,66 @@ +from _typeshed import Incomplete + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + +break_marker: Incomplete + +class CBORSimpleValue: + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + value: Incomplete + def __init__(self, value) -> None: ... + def __eq__(self, other): ... + def __repr__(self) -> str: ... + +def decode_uint(decoder, subtype, allow_indefinite: bool = False): ... +def decode_negint(decoder, subtype): ... +def decode_bytestring(decoder, subtype): ... +def decode_string(decoder, subtype): ... +def decode_array(decoder, subtype): ... +def decode_map(decoder, subtype): ... +def decode_special(decoder, subtype): ... +def decode_simple_value(decoder): ... +def decode_float16(decoder) -> None: ... +def decode_float32(decoder): ... +def decode_float64(decoder): ... + +major_decoders: Incomplete +special_decoders: Incomplete + +class CBORDecoder: + """ + Deserializes a CBOR encoded byte stream. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_encoder.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_encoder.py new file mode 100644 index 000000000..fe8715468 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_encoder.py @@ -0,0 +1,182 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + + +def encode_length(major_tag, length): + if length < 24: + return struct.pack(">B", major_tag | length) + elif length < 256: + return struct.pack(">BB", major_tag | 24, length) + elif length < 65536: + return struct.pack(">BH", major_tag | 25, length) + elif length < 4294967296: + return struct.pack(">BL", major_tag | 26, length) + else: + return struct.pack(">BQ", major_tag | 27, length) + + +def encode_semantic(encoder, tag, value): + encoder.write(encode_length(0xC0, tag)) + encoder.encode(value) + + +def encode_float(encoder, value): + # Handle special values efficiently + import math + + if math.isnan(value): + encoder.write(b"\xf9\x7e\x00") + elif math.isinf(value): + encoder.write(b"\xf9\x7c\x00" if value > 0 else b"\xf9\xfc\x00") + else: + encoder.write(struct.pack(">Bd", 0xFB, value)) + + +def encode_int(encoder, value): + # Big integers (2 ** 64 and over) + if value >= 18446744073709551616 or value < -18446744073709551616: + if value >= 0: + major_type = 0x02 + else: + major_type = 0x03 + value = -value - 1 + + values = [] + while value > 0: + value, remainder = divmod(value, 256) + values.insert(0, remainder) + + payload = bytes(values) + encode_semantic(encoder, major_type, payload) + elif value >= 0: + encoder.write(encode_length(0, value)) + else: + encoder.write(encode_length(0x20, abs(value) - 1)) + + +def encode_bytestring(encoder, value): + encoder.write(encode_length(0x40, len(value)) + value) + + +def encode_bytearray(encoder, value): + encode_bytestring(encoder, bytes(value)) + + +def encode_string(encoder, value): + encoded = value.encode("utf-8") + encoder.write(encode_length(0x60, len(encoded)) + encoded) + + +def encode_map(encoder, value): + encoder.write(encode_length(0xA0, len(value))) + for key, val in value.items(): + encoder.encode(key) + encoder.encode(val) + + +def encode_array(encoder, value): + encoder.write(encode_length(0x80, len(value))) + for item in value: + encoder.encode(item) + + +def encode_boolean(encoder, value): + encoder.write(b"\xf5" if value else b"\xf4") + + +def encode_none(encoder, value): + encoder.write(b"\xf6") + + +cbor_encoders = { # supported data types and the encoder to use. + bytes: encode_bytestring, + bytearray: encode_bytearray, + str: encode_string, + int: encode_int, + float: encode_float, + bool: encode_boolean, + type(None): encode_none, + list: encode_array, + dict: encode_map, +} + + +class CBOREncoder(object): + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + def __init__(self, fp): + self.fp = fp + + def _find_encoder(self, obj): + return cbor_encoders[type(obj)] + + def write(self, data): + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + self.fp.write(data) + + def encode(self, obj): + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + encoder = self._find_encoder(obj) + if not encoder: + raise CBOREncodeError("cannot serialize type %s" % type(obj)) + encoder(self, obj) + + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + fp = io.BytesIO() + dump(obj, fp, **kwargs) + return fp.getvalue() + + +def dump(obj, fp, **kwargs): + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ + CBOREncoder(fp, **kwargs).encode(obj) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_encoder.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_encoder.pyi new file mode 100644 index 000000000..8cd761686 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/cbor2/_encoder.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + +def encode_length(major_tag, length): ... +def encode_semantic(encoder, tag, value) -> None: ... +def encode_float(encoder, value) -> None: ... +def encode_int(encoder, value) -> None: ... +def encode_bytestring(encoder, value) -> None: ... +def encode_bytearray(encoder, value) -> None: ... +def encode_string(encoder, value) -> None: ... +def encode_map(encoder, value) -> None: ... +def encode_array(encoder, value) -> None: ... +def encode_boolean(encoder, value) -> None: ... +def encode_none(encoder, value) -> None: ... + +cbor_encoders: Incomplete + +class CBOREncoder: + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def _find_encoder(self, obj): ... + def write(self, data) -> None: + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + def encode(self, obj) -> None: + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + +def dump(obj, fp, **kwargs) -> None: + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/logging.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/logging.py new file mode 100644 index 000000000..edee407c6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/logging.py @@ -0,0 +1,253 @@ +from micropython import const +import io +import sys +import time + +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 + +_DEFAULT_LEVEL = WARNING + +_level_dict = { + CRITICAL: "CRITICAL", + ERROR: "ERROR", + WARNING: "WARNING", + INFO: "INFO", + DEBUG: "DEBUG", + NOTSET: "NOTSET", +} + +_loggers = {} +_stream = sys.stderr +_default_fmt = "%(levelname)s:%(name)s:%(message)s" +_default_datefmt = "%Y-%m-%d %H:%M:%S" + + +class LogRecord: + def set(self, name, level, message): + self.name = name + self.levelno = level + self.levelname = _level_dict[level] + self.message = message + self.ct = time.time() + self.msecs = int((self.ct - int(self.ct)) * 1000) + self.asctime = None + + +class Handler: + def __init__(self, level=NOTSET): + self.level = level + self.formatter = None + + def close(self): + pass + + def setLevel(self, level): + self.level = level + + def setFormatter(self, formatter): + self.formatter = formatter + + def format(self, record): + return self.formatter.format(record) + + +class StreamHandler(Handler): + def __init__(self, stream=None): + super().__init__() + self.stream = _stream if stream is None else stream + self.terminator = "\n" + + def close(self): + if hasattr(self.stream, "flush"): + self.stream.flush() + + def emit(self, record): + if record.levelno >= self.level: + self.stream.write(self.format(record) + self.terminator) + + +class FileHandler(StreamHandler): + def __init__(self, filename, mode="a", encoding="UTF-8"): + super().__init__(stream=open(filename, mode=mode, encoding=encoding)) + + def close(self): + super().close() + self.stream.close() + + +class Formatter: + def __init__(self, fmt=None, datefmt=None): + self.fmt = _default_fmt if fmt is None else fmt + self.datefmt = _default_datefmt if datefmt is None else datefmt + + def usesTime(self): + return "asctime" in self.fmt + + def formatTime(self, datefmt, record): + if hasattr(time, "strftime"): + return time.strftime(datefmt, time.localtime(record.ct)) + return None + + def format(self, record): + if self.usesTime(): + record.asctime = self.formatTime(self.datefmt, record) + return self.fmt % { + "name": record.name, + "message": record.message, + "msecs": record.msecs, + "asctime": record.asctime, + "levelname": record.levelname, + } + + +class Logger: + def __init__(self, name, level=NOTSET): + self.name = name + self.level = level + self.handlers = [] + self.record = LogRecord() + + def setLevel(self, level): + self.level = level + + def isEnabledFor(self, level): + return level >= self.getEffectiveLevel() + + def getEffectiveLevel(self): + return self.level or getLogger().level or _DEFAULT_LEVEL + + def log(self, level, msg, *args): + if self.isEnabledFor(level): + if args: + if isinstance(args[0], dict): + args = args[0] + msg = msg % args + self.record.set(self.name, level, msg) + handlers = self.handlers + if not handlers: + handlers = getLogger().handlers + for h in handlers: + h.emit(self.record) + + def debug(self, msg, *args): + self.log(DEBUG, msg, *args) + + def info(self, msg, *args): + self.log(INFO, msg, *args) + + def warning(self, msg, *args): + self.log(WARNING, msg, *args) + + def error(self, msg, *args): + self.log(ERROR, msg, *args) + + def critical(self, msg, *args): + self.log(CRITICAL, msg, *args) + + def exception(self, msg, *args, exc_info=True): + self.log(ERROR, msg, *args) + tb = None + if isinstance(exc_info, BaseException): + tb = exc_info + elif hasattr(sys, "exc_info"): + tb = sys.exc_info()[1] + if tb: + buf = io.StringIO() + sys.print_exception(tb, buf) + self.log(ERROR, buf.getvalue()) + + def addHandler(self, handler): + self.handlers.append(handler) + + def hasHandlers(self): + return len(self.handlers) > 0 + + +def getLogger(name=None): + if name is None: + name = "root" + if name not in _loggers: + _loggers[name] = Logger(name) + if name == "root": + basicConfig() + return _loggers[name] + + +def log(level, msg, *args): + getLogger().log(level, msg, *args) + + +def debug(msg, *args): + getLogger().debug(msg, *args) + + +def info(msg, *args): + getLogger().info(msg, *args) + + +def warning(msg, *args): + getLogger().warning(msg, *args) + + +def error(msg, *args): + getLogger().error(msg, *args) + + +def critical(msg, *args): + getLogger().critical(msg, *args) + + +def exception(msg, *args, exc_info=True): + getLogger().exception(msg, *args, exc_info=exc_info) + + +def shutdown(): + for k, logger in _loggers.items(): + for h in logger.handlers: + h.close() + _loggers.pop(logger, None) + + +def addLevelName(level, name): + _level_dict[level] = name + + +def basicConfig( + filename=None, + filemode="a", + format=None, + datefmt=None, + level=WARNING, + stream=None, + encoding="UTF-8", + force=False, +): + if "root" not in _loggers: + _loggers["root"] = Logger("root") + + logger = _loggers["root"] + + if force or not logger.handlers: + for h in logger.handlers: + h.close() + logger.handlers = [] + + if filename is None: + handler = StreamHandler(stream) + else: + handler = FileHandler(filename, filemode, encoding) + + handler.setLevel(level) + handler.setFormatter(Formatter(format, datefmt)) + + logger.setLevel(level) + logger.addHandler(handler) + + +if hasattr(sys, "atexit"): + sys.atexit(shutdown) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/logging.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/logging.pyi new file mode 100644 index 000000000..856bcccf7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/logging.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete +from micropython import const as const + +CRITICAL: int +ERROR: int +WARNING: int +INFO: int +DEBUG: int +NOTSET: int +_DEFAULT_LEVEL = WARNING +_level_dict: Incomplete +_loggers: Incomplete +_stream: Incomplete +_default_fmt: str +_default_datefmt: str + +class LogRecord: + name: Incomplete + levelno: Incomplete + levelname: Incomplete + message: Incomplete + ct: Incomplete + msecs: Incomplete + asctime: Incomplete + def set(self, name, level, message) -> None: ... + +class Handler: + level: Incomplete + formatter: Incomplete + def __init__(self, level=...) -> None: ... + def close(self) -> None: ... + def setLevel(self, level) -> None: ... + def setFormatter(self, formatter) -> None: ... + def format(self, record): ... + +class StreamHandler(Handler): + stream: Incomplete + terminator: str + def __init__(self, stream=None) -> None: ... + def close(self) -> None: ... + def emit(self, record) -> None: ... + +class FileHandler(StreamHandler): + def __init__(self, filename, mode: str = "a", encoding: str = "UTF-8") -> None: ... + def close(self) -> None: ... + +class Formatter: + fmt: Incomplete + datefmt: Incomplete + def __init__(self, fmt=None, datefmt=None) -> None: ... + def usesTime(self): ... + def formatTime(self, datefmt, record): ... + def format(self, record): ... + +class Logger: + name: Incomplete + level: Incomplete + handlers: Incomplete + record: Incomplete + def __init__(self, name, level=...) -> None: ... + def setLevel(self, level) -> None: ... + def isEnabledFor(self, level): ... + def getEffectiveLevel(self): ... + def log(self, level, msg, *args) -> None: ... + def debug(self, msg, *args) -> None: ... + def info(self, msg, *args) -> None: ... + def warning(self, msg, *args) -> None: ... + def error(self, msg, *args) -> None: ... + def critical(self, msg, *args) -> None: ... + def exception(self, msg, *args, exc_info: bool = True) -> None: ... + def addHandler(self, handler) -> None: ... + def hasHandlers(self): ... + +def getLogger(name=None): ... +def log(level, msg, *args) -> None: ... +def debug(msg, *args) -> None: ... +def info(msg, *args) -> None: ... +def warning(msg, *args) -> None: ... +def error(msg, *args) -> None: ... +def critical(msg, *args) -> None: ... +def exception(msg, *args, exc_info: bool = True) -> None: ... +def shutdown() -> None: ... +def addLevelName(level, name) -> None: ... +def basicConfig( + filename=None, filemode: str = "a", format=None, datefmt=None, level=..., stream=None, encoding: str = "UTF-8", force: bool = False +) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/modules.json new file mode 100644 index 000000000..ad6d4a321 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/modules.json @@ -0,0 +1,144 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "ARDUINO_OPTA", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "cbor2/__init__.py", + "module": "__init__" + }, + { + "file": "cbor2/_decoder.py", + "module": "_decoder" + }, + { + "file": "cbor2/_encoder.py", + "module": "_encoder" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "logging.py", + "module": "logging" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "msgpack.py", + "module": "msgpack" + }, + { + "file": "msgpackrpc.py", + "module": "msgpackrpc" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "opta.py", + "module": "opta" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "senml/__init__.py", + "module": "__init__" + }, + { + "file": "senml/senml_base.py", + "module": "senml_base" + }, + { + "file": "senml/senml_pack.py", + "module": "senml_pack" + }, + { + "file": "senml/senml_record.py", + "module": "senml_record" + }, + { + "file": "senml/senml_unit.py", + "module": "senml_unit" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "time.py", + "module": "time" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpack.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpack.py new file mode 100644 index 000000000..3f1f2683c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpack.py @@ -0,0 +1,860 @@ +# u-msgpack-python v2.8.0 - v at sergeev.io +# https://github.com/vsergeev/u-msgpack-python +# +# u-msgpack-python is a lightweight MessagePack serializer and deserializer +# module, compatible with both Python 2 and 3, as well CPython and PyPy +# implementations of Python. u-msgpack-python is fully compliant with the +# latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +# particular, it supports the new binary, UTF-8 string, and application ext +# types. +# +# MIT License +# +# Copyright (c) 2013-2023 vsergeev / Ivan (Vanya) A. Sergeev +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +""" +u-msgpack-python v2.8.0 - v at sergeev.io +https://github.com/vsergeev/u-msgpack-python + +u-msgpack-python is a lightweight MessagePack serializer and deserializer +module, compatible with both Python 2 and 3, as well CPython and PyPy +implementations of Python. u-msgpack-python is fully compliant with the +latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +particular, it supports the new binary, UTF-8 string, and application ext +types. + +License: MIT +""" + +import struct +import collections +import sys +import io + +__version__ = "2.8.0" +"Module version string" + +version = (2, 8, 0) +"Module version tuple" + + +############################################################################## +# Ext Class +############################################################################## + + +# Extension type for application-defined types and data +class Ext(object): + """ + The Ext class facilitates creating a serializable extension object to store + an application-defined type and data byte array. + """ + + def __init__(self, type, data): + """ + Construct a new Ext object. + + Args: + type (int): application-defined type integer + data (bytes): application-defined data byte array + + Raises: + TypeError: + Type is not an integer. + ValueError: + Type is out of range of -128 to 127. + TypeError: + Data is not type 'bytes' (Python 3) or not type 'str' (Python 2). + + Example: + >>> foo = umsgpack.Ext(5, b"\\x01\\x02\\x03") + >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) + '\\x82\\xa7awesome\\xc3\\xadspecial stuff\\xc7\\x03\\x05\\x01\\x02\\x03' + >>> bar = umsgpack.unpackb(_) + >>> print(bar["special stuff"]) + Ext Object (Type: 5, Data: 01 02 03) + """ + # Check type is type int and in range + if not isinstance(type, int): + raise TypeError("ext type is not type integer") + elif not (-(2**7) <= type <= 2**7 - 1): + raise ValueError("ext type value {:d} is out of range (-128 to 127)".format(type)) + # Check data is type bytes or str + elif sys.version_info[0] == 3 and not isinstance(data, bytes): + raise TypeError("ext data is not type 'bytes'") + elif sys.version_info[0] == 2 and not isinstance(data, str): + raise TypeError("ext data is not type 'str'") + + self.type = type + self.data = data + + def __eq__(self, other): + """ + Compare this Ext object with another for equality. + """ + return isinstance(other, self.__class__) and self.type == other.type and self.data == other.data + + def __ne__(self, other): + """ + Compare this Ext object with another for inequality. + """ + return not self.__eq__(other) + + def __str__(self): + """ + String representation of this Ext object. + """ + s = "Ext Object (Type: {:d}, Data: ".format(self.type) + s += " ".join(["0x{:02x}".format(ord(self.data[i : i + 1])) for i in range(min(len(self.data), 8))]) + if len(self.data) > 8: + s += " ..." + s += ")" + return s + + def __hash__(self): + """ + Provide a hash of this Ext object. + """ + return hash((self.type, self.data)) + + +class InvalidString(bytes): + """Subclass of bytes to hold invalid UTF-8 strings.""" + + +############################################################################## +# Ext Serializable Decorator +############################################################################## + +_ext_class_to_type = {} +_ext_type_to_class = {} + + +def ext_serializable(ext_type): + """ + Return a decorator to register a class for automatic packing and unpacking + with the specified Ext type code. The application class should implement a + `packb()` method that returns serialized bytes, and an `unpackb()` class + method or static method that accepts serialized bytes and returns an + instance of the application class. + + Args: + ext_type (int): application-defined Ext type code + + Raises: + TypeError: + Ext type is not an integer. + ValueError: + Ext type is out of range of -128 to 127. + ValueError: + Ext type or class already registered. + """ + + def wrapper(cls): + if not isinstance(ext_type, int): + raise TypeError("Ext type is not type integer") + elif not (-(2**7) <= ext_type <= 2**7 - 1): + raise ValueError("Ext type value {:d} is out of range of -128 to 127".format(ext_type)) + elif ext_type in _ext_type_to_class: + raise ValueError("Ext type {:d} already registered with class {:s}".format(ext_type, repr(_ext_type_to_class[ext_type]))) + elif cls in _ext_class_to_type: + raise ValueError("Class {:s} already registered with Ext type {:d}".format(repr(cls), ext_type)) + + _ext_type_to_class[ext_type] = cls + _ext_class_to_type[cls] = ext_type + + return cls + + return wrapper + + +############################################################################## +# Exceptions +############################################################################## + + +# Base Exception classes +class PackException(Exception): + "Base class for exceptions encountered during packing." + + +class UnpackException(Exception): + "Base class for exceptions encountered during unpacking." + + +# Packing error +class UnsupportedTypeException(PackException): + "Object type not supported for packing." + + +# Unpacking error +class InsufficientDataException(UnpackException): + "Insufficient data to unpack the serialized object." + + +class InvalidStringException(UnpackException): + "Invalid UTF-8 string encountered during unpacking." + + +class UnsupportedTimestampException(UnpackException): + "Unsupported timestamp format encountered during unpacking." + + +class ReservedCodeException(UnpackException): + "Reserved code encountered during unpacking." + + +class UnhashableKeyException(UnpackException): + """ + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + """ + + +class DuplicateKeyException(UnpackException): + "Duplicate key encountered during map unpacking." + + +############################################################################## +# Packing +############################################################################## + +# You may notice struct.pack("B", obj) instead of the simpler chr(obj) in the +# code below. This is to allow for seamless Python 2 and 3 compatibility, as +# chr(obj) has a str return type instead of bytes in Python 3, and +# struct.pack(...) has the right return type in both versions. + + +def _pack_integer(obj, fp, options): + if obj < 0: + if obj >= -32: + fp.write(struct.pack("b", obj)) + elif obj >= -(2 ** (8 - 1)): + fp.write(b"\xd0" + struct.pack("b", obj)) + elif obj >= -(2 ** (16 - 1)): + fp.write(b"\xd1" + struct.pack(">h", obj)) + elif obj >= -(2 ** (32 - 1)): + fp.write(b"\xd2" + struct.pack(">i", obj)) + elif obj >= -(2 ** (64 - 1)): + fp.write(b"\xd3" + struct.pack(">q", obj)) + else: + raise UnsupportedTypeException("huge signed int") + else: + if obj < 128: + fp.write(struct.pack("B", obj)) + elif obj < 2**8: + fp.write(b"\xcc" + struct.pack("B", obj)) + elif obj < 2**16: + fp.write(b"\xcd" + struct.pack(">H", obj)) + elif obj < 2**32: + fp.write(b"\xce" + struct.pack(">I", obj)) + elif obj < 2**64: + fp.write(b"\xcf" + struct.pack(">Q", obj)) + else: + raise UnsupportedTypeException("huge unsigned int") + + +def _pack_nil(obj, fp, options): + fp.write(b"\xc0") + + +def _pack_boolean(obj, fp, options): + fp.write(b"\xc3" if obj else b"\xc2") + + +def _pack_float(obj, fp, options): + float_precision = options.get("force_float_precision", "single") + + if float_precision == "double": + fp.write(b"\xcb" + struct.pack(">d", obj)) + elif float_precision == "single": + fp.write(b"\xca" + struct.pack(">f", obj)) + else: + raise ValueError("invalid float precision") + + +def _pack_string(obj, fp, options): + obj = obj.encode("utf-8") + obj_len = len(obj) + if obj_len < 32: + fp.write(struct.pack("B", 0xA0 | obj_len) + obj) + elif obj_len < 2**8: + fp.write(b"\xd9" + struct.pack("B", obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xda" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xdb" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge string") + + +def _pack_binary(obj, fp, options): + obj_len = len(obj) + if obj_len < 2**8: + fp.write(b"\xc4" + struct.pack("B", obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xc5" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xc6" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge binary string") + + +def _pack_oldspec_raw(obj, fp, options): + obj_len = len(obj) + if obj_len < 32: + fp.write(struct.pack("B", 0xA0 | obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xda" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xdb" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge raw string") + + +def _pack_ext(obj, fp, options): + obj_len = len(obj.data) + if obj_len == 1: + fp.write(b"\xd4" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 2: + fp.write(b"\xd5" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 4: + fp.write(b"\xd6" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 8: + fp.write(b"\xd7" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 16: + fp.write(b"\xd8" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len < 2**8: + fp.write(b"\xc7" + struct.pack("BB", obj_len, obj.type & 0xFF) + obj.data) + elif obj_len < 2**16: + fp.write(b"\xc8" + struct.pack(">HB", obj_len, obj.type & 0xFF) + obj.data) + elif obj_len < 2**32: + fp.write(b"\xc9" + struct.pack(">IB", obj_len, obj.type & 0xFF) + obj.data) + else: + raise UnsupportedTypeException("huge ext data") + + +def _pack_array(obj, fp, options): + obj_len = len(obj) + if obj_len < 16: + fp.write(struct.pack("B", 0x90 | obj_len)) + elif obj_len < 2**16: + fp.write(b"\xdc" + struct.pack(">H", obj_len)) + elif obj_len < 2**32: + fp.write(b"\xdd" + struct.pack(">I", obj_len)) + else: + raise UnsupportedTypeException("huge array") + + for e in obj: + pack(e, fp, **options) + + +def _pack_map(obj, fp, options): + obj_len = len(obj) + if obj_len < 16: + fp.write(struct.pack("B", 0x80 | obj_len)) + elif obj_len < 2**16: + fp.write(b"\xde" + struct.pack(">H", obj_len)) + elif obj_len < 2**32: + fp.write(b"\xdf" + struct.pack(">I", obj_len)) + else: + raise UnsupportedTypeException("huge array") + + for k, v in obj.items(): + pack(k, fp, **options) + pack(v, fp, **options) + + +# Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type +def pack(obj, fp, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + None + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> f = open('test.bin', 'wb') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + """ + ext_handlers = options.get("ext_handlers") + + if obj is None: + _pack_nil(obj, fp, options) + elif ext_handlers and obj.__class__ in ext_handlers: + _pack_ext(ext_handlers[obj.__class__](obj), fp, options) + elif obj.__class__ in _ext_class_to_type: + try: + _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) + elif isinstance(obj, bool): + _pack_boolean(obj, fp, options) + elif isinstance(obj, int): + _pack_integer(obj, fp, options) + elif isinstance(obj, float): + _pack_float(obj, fp, options) + elif isinstance(obj, str): + _pack_string(obj, fp, options) + elif isinstance(obj, bytes): + _pack_binary(obj, fp, options) + elif isinstance(obj, (list, tuple)): + _pack_array(obj, fp, options) + elif isinstance(obj, dict): + _pack_map(obj, fp, options) + elif isinstance(obj, Ext): + _pack_ext(obj, fp, options) + elif ext_handlers: + # Linear search for superclass + t = next((t for t in ext_handlers.keys() if isinstance(obj, t)), None) + if t: + _pack_ext(ext_handlers[t](obj), fp, options) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + elif _ext_class_to_type: + # Linear search for superclass + t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) + if t: + try: + _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + + +def packb(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + bytes: Serialized MessagePack bytes + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + b'\\x82\\xa7compact\\xc3\\xa6schema\\x00' + """ + fp = io.BytesIO() + pack(obj, fp, **options) + return fp.getvalue() + + +############################################################################# +# Unpacking +############################################################################# + + +def _read_except(fp, n): + if n == 0: + return b"" + + data = fp.read(n) + if len(data) == 0: + raise InsufficientDataException() + + while len(data) < n: + chunk = fp.read(n - len(data)) + if len(chunk) == 0: + raise InsufficientDataException() + + data += chunk + + return data + + +def _unpack_integer(code, fp, options): + if (ord(code) & 0xE0) == 0xE0: + return struct.unpack("b", code)[0] + elif code == b"\xd0": + return struct.unpack("b", _read_except(fp, 1))[0] + elif code == b"\xd1": + return struct.unpack(">h", _read_except(fp, 2))[0] + elif code == b"\xd2": + return struct.unpack(">i", _read_except(fp, 4))[0] + elif code == b"\xd3": + return struct.unpack(">q", _read_except(fp, 8))[0] + elif (ord(code) & 0x80) == 0x00: + return struct.unpack("B", code)[0] + elif code == b"\xcc": + return struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xcd": + return struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xce": + return struct.unpack(">I", _read_except(fp, 4))[0] + elif code == b"\xcf": + return struct.unpack(">Q", _read_except(fp, 8))[0] + raise Exception("logic error, not int: 0x{:02x}".format(ord(code))) + + +def _unpack_reserved(code, fp, options): + if code == b"\xc1": + raise ReservedCodeException("encountered reserved code: 0x{:02x}".format(ord(code))) + raise Exception("logic error, not reserved code: 0x{:02x}".format(ord(code))) + + +def _unpack_nil(code, fp, options): + if code == b"\xc0": + return None + raise Exception("logic error, not nil: 0x{:02x}".format(ord(code))) + + +def _unpack_boolean(code, fp, options): + if code == b"\xc2": + return False + elif code == b"\xc3": + return True + raise Exception("logic error, not boolean: 0x{:02x}".format(ord(code))) + + +def _unpack_float(code, fp, options): + if code == b"\xca": + return struct.unpack(">f", _read_except(fp, 4))[0] + elif code == b"\xcb": + return struct.unpack(">d", _read_except(fp, 8))[0] + raise Exception("logic error, not float: 0x{:02x}".format(ord(code))) + + +def _unpack_string(code, fp, options): + if (ord(code) & 0xE0) == 0xA0: + length = ord(code) & ~0xE0 + elif code == b"\xd9": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xda": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdb": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not string: 0x{:02x}".format(ord(code))) + + data = _read_except(fp, length) + try: + return bytes.decode(data, "utf-8") + except Exception: + if options.get("allow_invalid_utf8", True): + return InvalidString(data) + raise InvalidStringException("unpacked string is invalid utf-8") + + +def _unpack_binary(code, fp, options): + if code == b"\xc4": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xc5": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xc6": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not binary: 0x{:02x}".format(ord(code))) + + return _read_except(fp, length) + + +def _unpack_ext(code, fp, options): + if code == b"\xd4": + length = 1 + elif code == b"\xd5": + length = 2 + elif code == b"\xd6": + length = 4 + elif code == b"\xd7": + length = 8 + elif code == b"\xd8": + length = 16 + elif code == b"\xc7": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xc8": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xc9": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not ext: 0x{:02x}".format(ord(code))) + + ext_type = struct.unpack("b", _read_except(fp, 1))[0] + ext_data = _read_except(fp, length) + + # Unpack with ext handler, if we have one + ext_handlers = options.get("ext_handlers") + if ext_handlers and ext_type in ext_handlers: + return ext_handlers[ext_type](Ext(ext_type, ext_data)) + + # Unpack with ext classes, if type is registered + if ext_type in _ext_type_to_class: + try: + return _ext_type_to_class[ext_type].unpackb(ext_data) + except AttributeError: + raise NotImplementedError( + "Ext serializable class {:s} is missing implementation of unpackb()".format(repr(_ext_type_to_class[ext_type])) + ) + + return Ext(ext_type, ext_data) + + +def _unpack_array(code, fp, options): + if (ord(code) & 0xF0) == 0x90: + length = ord(code) & ~0xF0 + elif code == b"\xdc": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdd": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not array: 0x{:02x}".format(ord(code))) + + if options.get("use_tuple"): + return tuple((_unpack(fp, options) for i in range(length))) + + return [_unpack(fp, options) for i in range(length)] + + +def _deep_list_to_tuple(obj): + if isinstance(obj, list): + return tuple([_deep_list_to_tuple(e) for e in obj]) + return obj + + +def _unpack_map(code, fp, options): + if (ord(code) & 0xF0) == 0x80: + length = ord(code) & ~0xF0 + elif code == b"\xde": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdf": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not map: 0x{:02x}".format(ord(code))) + + d = {} if not options.get("use_ordered_dict") else collections.OrderedDict() + for _ in range(length): + # Unpack key + k = _unpack(fp, options) + + if isinstance(k, list): + # Attempt to convert list into a hashable tuple + k = _deep_list_to_tuple(k) + try: + hash(k) + except Exception: + raise UnhashableKeyException('encountered unhashable key: "{:s}" ({:s})'.format(str(k), str(type(k)))) + if k in d: + raise DuplicateKeyException('encountered duplicate key: "{:s}" ({:s})'.format(str(k), str(type(k)))) + + # Unpack value + v = _unpack(fp, options) + + try: + d[k] = v + except TypeError: + raise UnhashableKeyException('encountered unhashable key: "{:s}"'.format(str(k))) + return d + + +def _unpack(fp, options): + code = _read_except(fp, 1) + return _unpack_dispatch_table[code](code, fp, options) + + +def unpack(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {'compact': True, 'schema': 0} + """ + return _unpack(fp, options) + + +# For Python 3, expects a bytes object +def unpackb(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s (bytes, bytearray): serialized MessagePack bytes + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + TypeError: + Packed data type is neither 'bytes' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\\x82\\xa7compact\\xc3\\xa6schema\\x00') + {'compact': True, 'schema': 0} + """ + if not isinstance(s, (bytes, bytearray)): + raise TypeError("packed data must be type 'bytes' or 'bytearray'") + return _unpack(io.BytesIO(s), options) + + +############################################################################# +# Module Initialization +############################################################################# + + +def __init(): + global _unpack_dispatch_table + # Build a dispatch table for fast lookup of unpacking function + _unpack_dispatch_table = {} + # Fix uint + for code in range(0, 0x7F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fix map + for code in range(0x80, 0x8F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_map + # Fix array + for code in range(0x90, 0x9F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_array + # Fix str + for code in range(0xA0, 0xBF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Nil + _unpack_dispatch_table[b"\xc0"] = _unpack_nil + # Reserved + _unpack_dispatch_table[b"\xc1"] = _unpack_reserved + # Boolean + _unpack_dispatch_table[b"\xc2"] = _unpack_boolean + _unpack_dispatch_table[b"\xc3"] = _unpack_boolean + # Bin + for code in range(0xC4, 0xC6 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_binary + # Ext + for code in range(0xC7, 0xC9 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # Float + _unpack_dispatch_table[b"\xca"] = _unpack_float + _unpack_dispatch_table[b"\xcb"] = _unpack_float + # Uint + for code in range(0xCC, 0xCF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Int + for code in range(0xD0, 0xD3 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fixext + for code in range(0xD4, 0xD8 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # String + for code in range(0xD9, 0xDB + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Array + _unpack_dispatch_table[b"\xdc"] = _unpack_array + _unpack_dispatch_table[b"\xdd"] = _unpack_array + # Map + _unpack_dispatch_table[b"\xde"] = _unpack_map + _unpack_dispatch_table[b"\xdf"] = _unpack_map + # Negative fixint + for code in range(0xE0, 0xFF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + + +__init() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpack.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpack.pyi new file mode 100644 index 000000000..2dec10602 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpack.pyi @@ -0,0 +1,278 @@ +from _typeshed import Incomplete + +__version__: str +version: Incomplete + +class Ext: + """ + The Ext class facilitates creating a serializable extension object to store + an application-defined type and data byte array. + """ + + type: Incomplete + data: Incomplete + def __init__(self, type, data) -> None: + """ + Construct a new Ext object. + + Args: + type (int): application-defined type integer + data (bytes): application-defined data byte array + + Raises: + TypeError: + Type is not an integer. + ValueError: + Type is out of range of -128 to 127. + TypeError: + Data is not type \'bytes\' (Python 3) or not type \'str\' (Python 2). + + Example: + >>> foo = umsgpack.Ext(5, b"\\x01\\x02\\x03") + >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) + \'\\x82\\xa7awesome\\xc3\\xadspecial stuff\\xc7\\x03\\x05\\x01\\x02\\x03\' + >>> bar = umsgpack.unpackb(_) + >>> print(bar["special stuff"]) + Ext Object (Type: 5, Data: 01 02 03) + """ + def __eq__(self, other): + """ + Compare this Ext object with another for equality. + """ + def __ne__(self, other): + """ + Compare this Ext object with another for inequality. + """ + def __str__(self) -> str: + """ + String representation of this Ext object. + """ + def __hash__(self): + """ + Provide a hash of this Ext object. + """ + +class InvalidString(bytes): + """Subclass of bytes to hold invalid UTF-8 strings.""" + +_ext_class_to_type: Incomplete +_ext_type_to_class: Incomplete + +def ext_serializable(ext_type): + """ + Return a decorator to register a class for automatic packing and unpacking + with the specified Ext type code. The application class should implement a + `packb()` method that returns serialized bytes, and an `unpackb()` class + method or static method that accepts serialized bytes and returns an + instance of the application class. + + Args: + ext_type (int): application-defined Ext type code + + Raises: + TypeError: + Ext type is not an integer. + ValueError: + Ext type is out of range of -128 to 127. + ValueError: + Ext type or class already registered. + """ + +class PackException(Exception): + """Base class for exceptions encountered during packing.""" + +class UnpackException(Exception): + """Base class for exceptions encountered during unpacking.""" + +class UnsupportedTypeException(PackException): + """Object type not supported for packing.""" + +class InsufficientDataException(UnpackException): + """Insufficient data to unpack the serialized object.""" + +class InvalidStringException(UnpackException): + """Invalid UTF-8 string encountered during unpacking.""" + +class UnsupportedTimestampException(UnpackException): + """Unsupported timestamp format encountered during unpacking.""" + +class ReservedCodeException(UnpackException): + """Reserved code encountered during unpacking.""" + +class UnhashableKeyException(UnpackException): + """ + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + """ + +class DuplicateKeyException(UnpackException): + """Duplicate key encountered during map unpacking.""" + +def _pack_integer(obj, fp, options) -> None: ... +def _pack_nil(obj, fp, options) -> None: ... +def _pack_boolean(obj, fp, options) -> None: ... +def _pack_float(obj, fp, options) -> None: ... +def _pack_string(obj, fp, options) -> None: ... +def _pack_binary(obj, fp, options) -> None: ... +def _pack_oldspec_raw(obj, fp, options) -> None: ... +def _pack_ext(obj, fp, options) -> None: ... +def _pack_array(obj, fp, options) -> None: ... +def _pack_map(obj, fp, options) -> None: ... +def pack(obj, fp, **options) -> None: + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + None + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> f = open(\'test.bin\', \'wb\') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + """ + +def packb(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + bytes: Serialized MessagePack bytes + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + b\'\\x82\\xa7compact\\xc3\\xa6schema\\x00\' + """ + +def _read_except(fp, n): ... +def _unpack_integer(code, fp, options): ... +def _unpack_reserved(code, fp, options) -> None: ... +def _unpack_nil(code, fp, options) -> None: ... +def _unpack_boolean(code, fp, options): ... +def _unpack_float(code, fp, options): ... +def _unpack_string(code, fp, options): ... +def _unpack_binary(code, fp, options): ... +def _unpack_ext(code, fp, options): ... +def _unpack_array(code, fp, options): ... +def _deep_list_to_tuple(obj): ... +def _unpack_map(code, fp, options): ... +def _unpack(fp, options): ... +def unpack(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {'compact': True, 'schema': 0} + """ + +def unpackb(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s (bytes, bytearray): serialized MessagePack bytes + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + TypeError: + Packed data type is neither 'bytes' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\\x82\\xa7compact\\xc3\\xa6schema\\x00') + {'compact': True, 'schema': 0} + """ + +def __init() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpackrpc.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpackrpc.py new file mode 100644 index 000000000..e65c32e83 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpackrpc.py @@ -0,0 +1,202 @@ +# This file is part of the msgpack-rpc module. +# Copyright (c) 2023 Arduino SA +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# MessagePack RPC protocol implementation for MicroPython. +# https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md + +import logging +import openamp +import msgpack +from micropython import const +from io import BytesIO +from time import sleep_ms, ticks_ms, ticks_diff + +_MSG_TYPE_REQUEST = 0 +_MSG_TYPE_RESPONSE = 1 +_MSG_TYPE_NOTIFY = 2 + + +def log_level_enabled(level): + return logging.getLogger().isEnabledFor(level) + + +class Future: + def __init__(self, msgid, msgbuf, fname, fargs): + self.msgid = msgid + self.msgbuf = msgbuf + self.fname = fname + self.fargs = fargs + + def join(self, timeout=0): + if log_level_enabled(logging.DEBUG): + logging.debug(f"join {self.fname}()") + + if timeout > 0: + t = ticks_ms() + + while self.msgid not in self.msgbuf: + if timeout > 0 and ticks_diff(ticks_ms(), t) > timeout: + raise OSError(f"Timeout joining function {self.fname}") + sleep_ms(100) + + obj = self.msgbuf.pop(self.msgid) + if obj[2] is not None: + raise (OSError(obj[2])) + + if log_level_enabled(logging.DEBUG): + logging.debug(f"call {self.fname}({self.fargs}) => {obj}") + return obj[3] + + +class MsgPackIO: + def __init__(self): + self.stream = BytesIO() + + def feed(self, data): + offset = self.stream.tell() + self.stream.write(data) + self.stream.seek(offset) + + def readable(self): + if self.stream.read(1): + offset = self.stream.tell() + self.stream.seek(offset - 1) + return True + return False + + def truncate(self): + if self.readable(): + offset = self.stream.tell() + self.stream = BytesIO(self.stream.getvalue()[offset:]) + + def __iter__(self): + return self + + def __next__(self): + offset = self.stream.tell() + try: + obj = msgpack.unpack(self.stream) + self.truncate() + return obj + except Exception: + self.stream.seek(offset) + raise StopIteration + + +class MsgPackRPC: + def __init__(self, streaming=False): + """ + Create a MsgPack RPC object. + streaming: If True, messages can span multiple buffers, otherwise a buffer contains + exactly one full message. Note streaming mode is slower, so it should be disabled + if it's not needed. + """ + self.epts = {} + self.msgid = 0 + self.msgbuf = {} + self.msgio = MsgPackIO() if streaming else None + self.callables = {} + + def _bind_callback(self, src, name): + if log_level_enabled(logging.INFO): + logging.info(f'New service announcement src: {src} name: "{name}"') + self.epts[name] = openamp.Endpoint(name, self._recv_callback, dest=src) + self.epts[name].send(b"\x00") + + def _recv_callback(self, src, data): + if log_level_enabled(logging.DEBUG): + logging.debug(f"Received message on endpoint: {src} data: {bytes(data)}") + + if self.msgio is None: + obj = msgpack.unpackb(data) + self._process_unpacked_obj(obj) + else: + self.msgio.feed(data) + for obj in self.msgio: + self._process_unpacked_obj(obj) + + def _process_unpacked_obj(self, obj): + if obj[0] == _MSG_TYPE_RESPONSE: + self.msgbuf[obj[1]] = obj + elif obj[0] == _MSG_TYPE_REQUEST: + self._dispatch(obj[1], obj[2], obj[-1]) + if log_level_enabled(logging.DEBUG): + logging.debug(f"Unpacked {type(obj)} val: {obj}") + + def _send_msg(self, msgid, msgtype, fname, fargs, **kwargs): + timeout = kwargs.pop("timeout", 1000) + endpoint = kwargs.pop("endpoint", "rpc") + self.epts[endpoint].send(msgpack.packb([msgtype, msgid, fname, fargs]), timeout=timeout) + if msgtype == _MSG_TYPE_REQUEST: + self.msgid += 1 + return Future(msgid, self.msgbuf, fname, fargs) + + def _dispatch(self, msgid, fname, fargs): + retobj = None + error = None + + if fname in self.callables: + retobj = self.callables[fname](*fargs) + else: + error = "Unbound function called %s" % (fname) + + self._send_msg(msgid, _MSG_TYPE_RESPONSE, error, retobj) + + def bind(self, name, obj): + """ + Bind a callable or an object to a name. + name: The name to which the callable or object is bound. + obj: A callable or an object to bind to the name. If an object is passed, all of its + public methods will be bound to their respective qualified names. + """ + if callable(obj): + # Bind a single callable to its name. + self.callables[name] = obj + else: + # Bind all public methods of an object to their respective qualified names. + for k, v in obj.__class__.__dict__.items(): + if callable(v) and not k.startswith("_"): + self.callables[name + "." + k] = getattr(obj, k) + + def start(self, firmware=None, num_channels=2, timeout=3000): + """ + Initializes OpenAMP, loads the remote processor's firmware and starts. + firmware: A path to an elf file stored in the filesystem, or an address to an entry point in flash. + num_channels: The number of channels to wait for the remote processor to + create before starting to communicate with it. + timeout: How long to wait for the remote processor to start, 0 means forever. + """ + # Initialize OpenAMP and set the New Service callback. + openamp.new_service_callback(self._bind_callback) + + # Keep a reference to the remote processor object, to stop the GC from collecting + # it, which would call the finaliser and shut down the remote processor while it's + # still being used. + self.rproc = openamp.RemoteProc(firmware) + self.rproc.start() + + # Wait for remote processor to announce the end points. + t = ticks_ms() + while len(self.epts) != num_channels: + if timeout > 0 and ticks_diff(ticks_ms(), t) > timeout: + raise OSError("timeout waiting for the remote processor to start") + sleep_ms(10) + + # Introduce a brief delay to allow the M4 sufficient time + # to bind remote functions before invoking them. + sleep_ms(100) + + def call(self, fname, *args, **kwargs): + """ + Synchronous call. The client is blocked until the RPC is finished. + """ + return self.call_async(fname, *args, *kwargs).join() + + def call_async(self, fname, *args, **kwargs): + """ + Asynchronous call. The client returns a Future object immediately. + """ + return self._send_msg(self.msgid, _MSG_TYPE_REQUEST, fname, list(args), *kwargs) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpackrpc.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpackrpc.pyi new file mode 100644 index 000000000..25c365b6d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/msgpackrpc.pyi @@ -0,0 +1,68 @@ +from _typeshed import Incomplete +from micropython import const as const + +_MSG_TYPE_REQUEST: int +_MSG_TYPE_RESPONSE: int +_MSG_TYPE_NOTIFY: int + +def log_level_enabled(level): ... + +class Future: + msgid: Incomplete + msgbuf: Incomplete + fname: Incomplete + fargs: Incomplete + def __init__(self, msgid, msgbuf, fname, fargs) -> None: ... + def join(self, timeout: int = 0): ... + +class MsgPackIO: + stream: Incomplete + def __init__(self) -> None: ... + def feed(self, data) -> None: ... + def readable(self): ... + def truncate(self) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class MsgPackRPC: + epts: Incomplete + msgid: int + msgbuf: Incomplete + msgio: Incomplete + callables: Incomplete + def __init__(self, streaming: bool = False) -> None: + """ + Create a MsgPack RPC object. + streaming: If True, messages can span multiple buffers, otherwise a buffer contains + exactly one full message. Note streaming mode is slower, so it should be disabled + if it's not needed. + """ + def _bind_callback(self, src, name) -> None: ... + def _recv_callback(self, src, data) -> None: ... + def _process_unpacked_obj(self, obj) -> None: ... + def _send_msg(self, msgid, msgtype, fname, fargs, **kwargs): ... + def _dispatch(self, msgid, fname, fargs) -> None: ... + def bind(self, name, obj) -> None: + """ + Bind a callable or an object to a name. + name: The name to which the callable or object is bound. + obj: A callable or an object to bind to the name. If an object is passed, all of its + public methods will be bound to their respective qualified names. + """ + rproc: Incomplete + def start(self, firmware=None, num_channels: int = 2, timeout: int = 3000) -> None: + """ + Initializes OpenAMP, loads the remote processor's firmware and starts. + firmware: A path to an elf file stored in the filesystem, or an address to an entry point in flash. + num_channels: The number of channels to wait for the remote processor to + create before starting to communicate with it. + timeout: How long to wait for the remote processor to start, 0 means forever. + """ + def call(self, fname, *args, **kwargs): + """ + Synchronous call. The client is blocked until the RPC is finished. + """ + def call_async(self, fname, *args, **kwargs): + """ + Asynchronous call. The client returns a Future object immediately. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/opta.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/opta.py new file mode 100644 index 000000000..0c95ac9b2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/opta.py @@ -0,0 +1,444 @@ +# This file is part of the blueprint package. +# Copyright (c) 2024 Arduino SA +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +import struct +import logging +from time import sleep_ms +from machine import I2C +from machine import Pin +from micropython import const + +_MIN_ADDRESS = 0x0B +_TMP_ADDRESS = 0x0A +_MAX_ADDRESS = const(0x0B + 0x0A) + +# Header and CRC length. +_CMD_HDR_LEN = 0x03 +_CMD_CRC_LEN = 0x01 + +# Command direction (SET == 1, GET == 2) +_CMD_DIR_SET = 0x01 +_CMD_DIR_GET = 0x02 + +# Commands are encoded as follows: +# [direction, command opcode, response length, ack required] +_CMD_CHIP_RESET = (_CMD_DIR_SET, 0x01, 0, False) +_CMD_SET_ADDRESS = (_CMD_DIR_SET, 0x02, 0, False) +_CMD_GET_ADDRESS = (_CMD_DIR_GET, 0x03, 2, False) + +# Misc commands such as product ID, firmware etc... +_CMD_GET_PRODUCT_ID = (_CMD_DIR_GET, 0x25, 33, False) +_CMD_GET_FW_VERSION = (_CMD_DIR_GET, 0x16, 3, False) +_CMD_SET_BOOTLOADER = (_CMD_DIR_SET, 0xF3, 0, False) + +# Flash commands. +_CMD_SET_FLASH_WRITE = (_CMD_DIR_SET, 0x17, 0, False) +_CMD_GET_FLASH_READ = (_CMD_DIR_GET, 0x18, 32, False) + +# Digital pins commands. +_CMD_SET_DIGITAL_PIN = (_CMD_DIR_SET, 0x06, 0, False) +_CMD_GET_DIGITAL_BUS = (_CMD_DIR_GET, 0x04, 2, False) +_CMD_SET_DIGITAL_DEF = (_CMD_DIR_SET, 0x08, 0, False) +_CMD_SET_DIGITAL_BUS_OA = (_CMD_DIR_SET, 0x15, 0, True) + +# Analog channels commands. +_CMD_CFG_ANALOG_ADC = (_CMD_DIR_SET, 0x09, 0, True) +_CMD_CFG_ANALOG_DIN = (_CMD_DIR_SET, 0x11, 0, True) +_CMD_CFG_ANALOG_PWM = (_CMD_DIR_SET, 0x13, 0, True) +_CMD_CFG_ANALOG_DAC = (_CMD_DIR_SET, 0x0C, 0, True) +_CMD_CFG_ANALOG_RTD = (_CMD_DIR_SET, 0x0E, 0, True) +_CMD_CFG_ANALOG_HIZ = (_CMD_DIR_SET, 0x24, 0, True) +_CMD_SET_ANALOG_DAC = (_CMD_DIR_SET, 0x0D, 0, True) +_CMD_SET_ANALOG_RTD_TIM = (_CMD_DIR_SET, 0x10, 0, True) + +# Read analog channels (Analog pin, ADC, RTD, Digital In) +_CMD_GET_ANALOG_PIN = (_CMD_DIR_GET, 0x05, 2, False) +_CMD_GET_ANALOG_PIN_ALL = (_CMD_DIR_GET, 0x07, 32, False) +_CMD_GET_ANALOG_ADC = (_CMD_DIR_GET, 0x0A, 3, False) +_CMD_GET_ANALOG_ADC_ALL = (_CMD_DIR_GET, 0x0B, 16, False) +_CMD_GET_ANALOG_RTD = (_CMD_DIR_GET, 0x0F, 5, False) +_CMD_GET_ANALOG_DIN = (_CMD_DIR_GET, 0x12, 1, False) + +# Default analog channels values and timeout. +_CMD_SET_ANALOG_PWM_DEF = (_CMD_DIR_SET, 0x33, 0, True) +_CMD_SET_ANALOG_DAC_DEF = (_CMD_DIR_SET, 0x3D, 0, True) +_CMD_SET_ANALOG_TIMEOUT = (_CMD_DIR_SET, 0x31, 0, True) + +_CHANNEL_MODES = (None, "voltage", "current") +_CHANNEL_TYPES = ("adc", "dac", "rtd", "pwm", "hiz", "din") + + +class Expansion: + def __init__(self, opta, type, addr, name): + self.opta = opta + self.type = type + self.addr = addr + self.name = name + self.channels = {} + + def product_id(self): + """ + Returns the product ID bytes of the expansion. + """ + return self.opta._cmd(self.addr, _CMD_GET_PRODUCT_ID) + + def firmware_version(self): + """ + Returns the firmware version of the expansion. + """ + return self.opta._cmd(self.addr, _CMD_GET_FW_VERSION) + + def _flash(self, address, size=0, data=None): + """ + Reads from or writes to the flash memory at the specified address. + + NOTE: This should be used for production purposes only! + + Parameters: + - address : The memory address to read from or write to. + - size : Number of bytes to read from the flash memory. + - data : Bytes to write to the flash memory. + + Returns: + Data read from the flash memory as bytes, if reading. Returns None if writing. + """ + size = size if data is None else len(data) + if size < 0 or size > 32: + raise RuntimeError("Maximum flash read/write size is 32") + if data is None: + resp = self.opta._cmd(self.addr, _CMD_GET_FLASH_READ, " 7): + raise ValueError("Invalid channel specified") + if self.type == "digital" and (channel < 0 or channel > 16): + raise ValueError("Invalid channel specified") + + # Set default analog channels timeout. + if timeout is not None: + if self.type != "analog": + raise RuntimeError("Function is not supported on digital expansions") + return self.opta._cmd(self.addr, _CMD_SET_ANALOG_TIMEOUT, " 4: + raise ValueError("Invalid PWM channel specified") + if "period" not in kwargs: + raise ValueError("PWM requires a period argument") + period = kwargs["period"] + duty = int(kwargs.get("duty", 50) / 100 * period) + self.opta._cmd(self.addr, _CMD_CFG_ANALOG_PWM, " None: ... + def product_id(self): + """ + Returns the product ID bytes of the expansion. + """ + def firmware_version(self): + """ + Returns the firmware version of the expansion. + """ + def _flash(self, address, size: int = 0, data=None): + """ + Reads from or writes to the flash memory at the specified address. + + NOTE: This should be used for production purposes only! + + Parameters: + - address : The memory address to read from or write to. + - size : Number of bytes to read from the flash memory. + - data : Bytes to write to the flash memory. + + Returns: + Data read from the flash memory as bytes, if reading. Returns None if writing. + """ + def digital(self, pins=None, timeout=None, default: int = 0): + """ + Reads or writes digital pins. + + Parameters: + - pins : Digital pins mask to set. If None, returns the state of all pins. + - timeout : The timeout in milliseconds, after which pins revert to the default state. + - default : The default state to which the pins will revert to after the timeout expires. + + Note: + - For Opta Analog, this functions supports writing digital LEDs only. + + Returns: The current state of the digital pins if reading, or None if setting the pins. + """ + def analog(self, channel=None, channel_type=None, channel_mode=None, timeout=None, **kwargs): + """ + Configures or reads analog channels. + + Parameters: + - timeout : Set timeout in milliseconds after which analog channels revert to their default + states set previously with analog(). Note if this is set, all other args are ignored. + - channel : The channel number to configure, read, or write. If None, reads all ADC channels. + - channel_type : Channel type can be "adc", "dac", "pwm", "rtd", "hiz", "din". + - channel_mode : "voltage" or "current" (default="voltage" for ADC channels). + + kwargs : + hiz configuration: + - no args. + + adc configuration: + - average : Number of points for moving average (0-255, default=0). + - rejection : Enable rejection (default=False). + - diagnostic : Enable diagnostic (default=False). + - pulldown : Enable pulldown (default=True for voltage, False for current). + - secondary : This ADC channel is shared with another function (default=False). + + dac configuration: + - use_slew : Enable slew rate control (default=False). + - slew_rate : Slew rate if `use_slew` is True (default=0). + - limit_current : Limit current (default=False). + - value : Value to write to a DAC channel. + - default_value: The default value to revert to, after the timeout set with timeout() expires. + + pwm configuration: + - period: PWM period in uS (for example 1000uS). + - duty: high duty cycle in % (for example 50%). + - default_period: The default value to revert to, after the timeout set with timeout() expires. + - default_duty: The default value to revert to, after the timeout set with timeout() expires. + + rtd configuration: + - use_3_wire: 3-Wire RTD (default = False). + - current_ma: RTD current in mA (default = 1.2mA). + - update_time: The update time of all RDT channels. + + din (digital input) configuration: + - comparator : Enable comparator (default=True). + - filtered : Select the filtered input to the comparator (default=True). + - inverted : Invert the output from the digital input comparator (default=False). + - scale : Comparator voltage scale (default=False). + - threshold : Comparator voltage threshold (default 9). + - sink : Sets the sink current in digital input logic mode (0-31, default 1) + - debounce_mode : Debounce mode ("simple", "integrator" or None to disable debounce, default="simple") + - debounce_time : Debounce time (0-31, default 24) + + Returns: ADC value(s) if reading, or None if configuring a channel or setting the analog timeout. + """ + +class Opta: + bus: Incomplete + cmd_buf: Incomplete + det: Incomplete + exp_types: Incomplete + def __init__(self, bus_id, freq: int = 400000, det=None) -> None: + """ + Initializes an Opta controller. + + Parameters: + - bus_id : The I2C bus identifier. + - freq : I2C bus frequency (default=400_000). + - det : GPIO pin used for bus detection (default is a PULL_UP input pin named "BUS_DETECT"). + """ + def _log_debug(self, msg) -> None: ... + def _log_enabled(self, level): ... + def _bus_read(self, addr, buf) -> None: ... + def _bus_write(self, addr, buf) -> None: ... + def _crc8(self, buf, poly: int = 7, crc: int = 0): ... + def _cmd(self, addr, cmd, fmt=None, *args): ... + def _reset_bus(self, addr) -> None: ... + def _set_address(self, addr, addr_new=None): ... + def enum_devices(self): + """ + Initializes the bus, resets all expansions, and returns a list of detected expansions. + Returns: A list of detected expansions on the bus. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/__init__.py new file mode 100644 index 000000000..908375fdb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/__init__.py @@ -0,0 +1,29 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from .senml_base import SenmlBase +from .senml_pack import SenmlPack +from .senml_record import SenmlRecord +from .senml_unit import SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/__init__.pyi new file mode 100644 index 000000000..c72285dc4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/__init__.pyi @@ -0,0 +1,4 @@ +from .senml_base import SenmlBase as SenmlBase +from .senml_pack import SenmlPack as SenmlPack +from .senml_record import SenmlRecord as SenmlRecord +from .senml_unit import SenmlUnits as SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_base.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_base.py new file mode 100644 index 000000000..b277c9477 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_base.py @@ -0,0 +1,30 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +class SenmlBase(object): + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_base.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_base.pyi new file mode 100644 index 000000000..240f185ce --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_base.pyi @@ -0,0 +1,4 @@ +class SenmlBase: + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_pack.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_pack.py new file mode 100644 index 000000000..5a0554467 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_pack.py @@ -0,0 +1,358 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from senml.senml_record import SenmlRecord +from senml.senml_base import SenmlBase +import json +import cbor2 + + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + def __init__(self, list): + self._list = list + self._index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self._index < len(self._list): + res = self._list[self._index] + self._index += 1 + return res + else: + raise StopIteration + + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings = { + "bn": "bn", + "bt": "bt", + "bu": "bu", + "bv": "bv", + "bs": "bs", + "n": "n", + "u": "u", + "v": "v", + "vs": "vs", + "vb": "vb", + "vd": "vd", + "s": "s", + "t": "t", + "ut": "ut", + } + + def __init__(self, name, callback=None): + """ + initialize the object + :param name: {string} the name of the pack + """ + self._data = [] + self.name = name + self._base_value = None + self._base_time = None + self._base_sum = None + self.base_unit = None + self._parent = None # a pack can also be the child of another pack. + self.actuate = callback # actuate callback function + + def __iter__(self): + return SenmlPackIterator(self._data) + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + return self._base_value + + @base_value.setter + def base_value(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_value") + self._base_value = value + + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + return self._base_sum + + @base_sum.setter + def base_sum(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_sum") + self._base_sum = value + + @property + def base_time(self): + return self._base_time + + @base_time.setter + def base_time(self, value): + self._check_value_type(value, "base_time") + self._base_time = value + + def _check_value_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + def from_json(self, data): + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + records = json.loads(data) # load the raw senml data + self._process_incomming_data(records, SenmlPack.json_mappings) + + def _process_incomming_data(self, records, naming_map): + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + cur_pack_el = self + new_pack = False + for item in records: + if naming_map["bn"] in item: # ref to a pack element, either this or a child pack. + if item[naming_map["bn"]] != self.name: + pack_el = [x for x in self._data if x.name == item[naming_map["bn"]]] + else: + pack_el = [self] + if len(pack_el) > 0: + cur_pack_el = pack_el[0] + new_pack = False + else: + device = SenmlPack(item[naming_map["bn"]]) + self._data.append(device) + cur_pack_el = device + new_pack = True + + if ( + naming_map["bv"] in item + ): # need to copy the base value assigned to the pack element so we can do proper conversion for actuators. + cur_pack_el.base_value = item[naming_map["bv"]] + + rec_el = [x for x in cur_pack_el._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + else: + rec_el = [x for x in self._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + + def do_actuate(self, raw, naming_map, device=None): + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + rec = SenmlRecord(raw[naming_map["n"]]) + if device: + device.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=device) + else: + self.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=None) + + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + converted = [] + self._build_rec_dict(SenmlPack.json_mappings, converted) + return json.dumps(converted) + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + internalList = [] + for item in self._data: + item._build_rec_dict(naming_map, internalList) + if len(internalList) > 0: + first_rec = internalList[0] + else: + first_rec = {} + internalList.append(first_rec) + + if self.name: + first_rec[naming_map["bn"]] = self.name + if self.base_value: + first_rec[naming_map["bv"]] = self.base_value + if self.base_unit: + first_rec[naming_map["bu"]] = self.base_unit + if self.base_sum: + first_rec[naming_map["bs"]] = self.base_sum + if self.base_time: + first_rec[naming_map["bt"]] = self.base_time + appendTo.extend(internalList) + + def from_cbor(self, data): + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + records = cbor2.loads(data) # load the raw senml data + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + self._process_incomming_data(records, naming_map) + + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + converted = [] + self._build_rec_dict(naming_map, converted) + return cbor2.dumps(converted) + + def add(self, item): + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if item._parent is not None: + raise Exception("item is already part of a pack") + + self._data.append(item) + item._parent = self + + def remove(self, item): + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if not item._parent == self: + raise Exception("item is not part of this pack") + + self._data.remove(item) + item._parent = None + + def clear(self): + """ + clear the list of the pack + :return: None + """ + for item in self._data: + item._parent = None + self._data = [] diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_pack.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_pack.pyi new file mode 100644 index 000000000..57a0cf547 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_pack.pyi @@ -0,0 +1,143 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase +from senml.senml_record import SenmlRecord as SenmlRecord + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + _list: Incomplete + _index: int + def __init__(self, list) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings: Incomplete + _data: Incomplete + name: Incomplete + _base_value: Incomplete + _base_time: Incomplete + _base_sum: Incomplete + base_unit: Incomplete + _parent: Incomplete + actuate: Incomplete + def __init__(self, name, callback=None) -> None: + """ + initialize the object + :param name: {string} the name of the pack + """ + def __iter__(self): ... + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + @base_value.setter + def base_value(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + @base_sum.setter + def base_sum(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_time(self): ... + @base_time.setter + def base_time(self, value) -> None: ... + def _check_value_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def from_json(self, data) -> None: + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + def _process_incomming_data(self, records, naming_map) -> None: + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + def do_actuate(self, raw, naming_map, device=None) -> None: + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + def from_cbor(self, data) -> None: + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + def add(self, item) -> None: + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + def remove(self, item) -> None: + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + def clear(self) -> None: + """ + clear the list of the pack + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_record.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_record.py new file mode 100644 index 000000000..b5b07b0bc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_record.py @@ -0,0 +1,240 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import binascii +from senml.senml_base import SenmlBase + + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + def __init__(self, name, **kwargs): + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + self.__parent = None # using double __ cause it's a field for an internal property + self._unit = None # declare and init internal fields + self._value = None + self._time = None + self._sum = None + self._update_time = None + + self._parent = None # internal reference to the parent object + self.name = name + self.unit = kwargs.get("unit", None) + self.value = kwargs.get("value", None) + self.time = kwargs.get("time", None) + self.sum = kwargs.get("sum", None) + self.update_time = kwargs.get("update_time", None) + self.actuate = kwargs.get("callback", None) # actuate callback function + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + def _check_value_type(self, value): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not ( + isinstance(value, bool) + or isinstance(value, int) + or isinstance(value, float) + or isinstance(value, bytearray) + or isinstance(value, str) + ): + raise Exception("invalid type for value, only numbers, strings, boolean and byte arrays allowed") + + def _check_number_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + @property + def value(self): + """get the value currently assigned to the object""" + return self._value + + @value.setter + def value(self, value): + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + self._check_value_type(value) + self._value = value + + @property + def time(self): + return self._time + + @time.setter + def time(self, value): + self._check_number_type(value, "time") + self._time = value + + @property + def update_time(self): + return self._update_time + + @update_time.setter + def update_time(self, value): + self._check_number_type(value, "update_time") + self._update_time = value + + @property + def sum(self): + return self._sum + + @sum.setter + def sum(self, value): + self._check_number_type(value, "sum") + self._sum = value + + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + return self.__parent + + @_parent.setter + def _parent(self, value): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + self.__parent = value + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + result = {} + + if self.name: + result[naming_map["n"]] = self.name + + if self._sum: + if self._parent and self._parent.base_sum: + result[naming_map["s"]] = self._sum - self._parent.base_sum + else: + result[naming_map["s"]] = self._sum + elif isinstance(self._value, bool): + result[naming_map["vb"]] = self._value + elif isinstance(self._value, int) or isinstance(self._value, float): + if self._parent and self._parent.base_value: + result[naming_map["v"]] = self._value - self._parent.base_value + else: + result[naming_map["v"]] = self._value + elif isinstance(self._value, str): + result[naming_map["vs"]] = self._value + elif isinstance(self._value, bytearray): + if naming_map["vd"] == "vd": # neeed to make a distinction between json (needs base64) and cbor (needs binary) + result[naming_map["vd"]] = binascii.b2a_base64(self._value, newline=False).decode("utf8") + else: + result[naming_map["vd"]] = self._value + else: + raise Exception("sum or value of type bootl, number, string or byte-array is required") + + if self._time: + if self._parent and self._parent.base_time: + result[naming_map["t"]] = self._time - self._parent.base_time + else: + result[naming_map["t"]] = self._time + + if self.unit: + result[naming_map["u"]] = self.unit + + if self._update_time: + if self._parent and self._parent.base_time: + result[naming_map["ut"]] = self._update_time - self._parent.base_time + else: + result[naming_map["ut"]] = self._update_time + + appendTo.append(result) + + def _from_raw(self, raw, naming_map): + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + if naming_map["v"] in raw: + val = raw[naming_map["v"]] + if self._parent and self._parent.base_value: + val += self._parent.base_value + elif naming_map["vs"] in raw: + val = raw[naming_map["vs"]] + elif naming_map["vb"] in raw: + val = raw[naming_map["vb"]] + elif naming_map["vd"] in raw: + val = binascii.a2b_base64(raw[naming_map["vb"]]) + else: + val = None + self.value = val + + def do_actuate(self, raw, naming_map): + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ + self._from_raw(raw, naming_map) + if self.actuate: + self.actuate(self) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_record.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_record.pyi new file mode 100644 index 000000000..61c0c7c05 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_record.pyi @@ -0,0 +1,104 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + __parent: Incomplete + _unit: Incomplete + _value: Incomplete + _time: Incomplete + _sum: Incomplete + _update_time: Incomplete + name: Incomplete + unit: Incomplete + actuate: Incomplete + def __init__(self, name, **kwargs) -> None: + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + def _check_value_type(self, value) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def _check_number_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + @property + def value(self): + """get the value currently assigned to the object""" + @value.setter + def value(self, value) -> None: + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + @property + def time(self): ... + @time.setter + def time(self, value) -> None: ... + @property + def update_time(self): ... + @update_time.setter + def update_time(self, value) -> None: ... + @property + def sum(self): ... + @sum.setter + def sum(self, value) -> None: ... + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + @_parent.setter + def _parent(self, value) -> None: + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + def _from_raw(self, raw, naming_map) -> None: + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + def do_actuate(self, raw, naming_map) -> None: + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_unit.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_unit.py new file mode 100644 index 000000000..bf7753c4d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_unit.py @@ -0,0 +1,89 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +def enum(**enums): + return type("Enum", (), enums) + + +SenmlUnits = enum( + SENML_UNIT_METER="m", + SENML_UNIT_KILOGRAM="kg", + SENML_UNIT_GRAM="g", + SENML_UNIT_SECOND="s", + SENML_UNIT_AMPERE="A", + SENML_UNIT_KELVIN="K", + SENML_UNIT_CANDELA="cd", + SENML_UNIT_MOLE="mol", + SENML_UNIT_HERTZ="Hz", + SENML_UNIT_RADIAN="rad", + SENML_UNIT_STERADIAN="sr", + SENML_UNIT_NEWTON="N", + SENML_UNIT_PASCAL="Pa", + SENML_UNIT_JOULE="J", + SENML_UNIT_WATT="W", + SENML_UNIT_COULOMB="C", + SENML_UNIT_VOLT="V", + SENML_UNIT_FARAD="F", + SENML_UNIT_OHM="Ohm", + SENML_UNIT_SIEMENS="S", + SENML_UNIT_WEBER="Wb", + SENML_UNIT_TESLA="T", + SENML_UNIT_HENRY="H", + SENML_UNIT_DEGREES_CELSIUS="Cel", + SENML_UNIT_LUMEN="lm", + SENML_UNIT_LUX="lx", + SENML_UNIT_BECQUEREL="Bq", + SENML_UNIT_GRAY="Gy", + SENML_UNIT_SIEVERT="Sv", + SENML_UNIT_KATAL="kat", + SENML_UNIT_SQUARE_METER="m2", + SENML_UNIT_CUBIC_METER="m3", + SENML_UNIT_LITER="l", + SENML_UNIT_VELOCITY="m/s", + SENML_UNIT_ACCELERATION="m/s2", + SENML_UNIT_CUBIC_METER_PER_SECOND="m3/s", + SENML_UNIT_LITER_PER_SECOND="l/s", + SENML_UNIT_WATT_PER_SQUARE_METER="W/m2", + SENML_UNIT_CANDELA_PER_SQUARE_METER="cd/m2", + SENML_UNIT_BIT="bit", + SENML_UNIT_BIT_PER_SECOND="bit/s", + SENML_UNIT_DEGREES_LATITUDE="lat", + SENML_UNIT_DEGREES_LONGITUDE="lon", + SENML_UNIT_PH="pH", + SENML_UNIT_DECIBEL="db", + SENML_UNIT_DECIBEL_RELATIVE_TO_1_W="dBW", + SENML_UNIT_BEL="Bspl", + SENML_UNIT_COUNTER="count", + SENML_UNIT_RATIO="//", + SENML_UNIT_RELATIVE_HUMIDITY="%RH", + SENML_UNIT_PERCENTAGE_REMAINING_BATTERY_LEVEL="%EL", + SENML_UNIT_SECONDS_REMAINING_BATTERY_LEVEL="EL", + SENML_UNIT_EVENT_RATE_PER_SECOND="1/s", + SENML_UNIT_EVENT_RATE_PER_MINUTE="1/min", + SENML_UNIT_BPM="beat/min", + SENML_UNIT_BEATS="beats", + SENML_UNIT_SIEMENS_PER_METER="S/m", +) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_unit.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_unit.pyi new file mode 100644 index 000000000..6b3e7ae68 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/senml/senml_unit.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +def enum(**enums): ... + +SenmlUnits: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/time.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/time.py new file mode 100644 index 000000000..f79ab8a3b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/time.py @@ -0,0 +1,79 @@ +from utime import * +from micropython import const + +_TS_YEAR = 0 +_TS_MON = 1 +_TS_MDAY = 2 +_TS_HOUR = 3 +_TS_MIN = 4 +_TS_SEC = 5 +_TS_WDAY = 6 +_TS_YDAY = 7 +_TS_ISDST = 8 + +_WDAY = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") +_MDAY = const( + ( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ) +) + + +def strftime(datefmt, ts): + from io import StringIO + + fmtsp = False + ftime = StringIO() + for k in datefmt: + if fmtsp: + if k == "a": + ftime.write(_WDAY[ts[_TS_WDAY]][0:3]) + elif k == "A": + ftime.write(_WDAY[ts[_TS_WDAY]]) + elif k == "b": + ftime.write(_MDAY[ts[_TS_MON] - 1][0:3]) + elif k == "B": + ftime.write(_MDAY[ts[_TS_MON] - 1]) + elif k == "d": + ftime.write("%02d" % ts[_TS_MDAY]) + elif k == "H": + ftime.write("%02d" % ts[_TS_HOUR]) + elif k == "I": + ftime.write("%02d" % (ts[_TS_HOUR] % 12)) + elif k == "j": + ftime.write("%03d" % ts[_TS_YDAY]) + elif k == "m": + ftime.write("%02d" % ts[_TS_MON]) + elif k == "M": + ftime.write("%02d" % ts[_TS_MIN]) + elif k == "P": + ftime.write("AM" if ts[_TS_HOUR] < 12 else "PM") + elif k == "S": + ftime.write("%02d" % ts[_TS_SEC]) + elif k == "w": + ftime.write(str(ts[_TS_WDAY])) + elif k == "y": + ftime.write("%02d" % (ts[_TS_YEAR] % 100)) + elif k == "Y": + ftime.write(str(ts[_TS_YEAR])) + else: + ftime.write(k) + fmtsp = False + elif k == "%": + fmtsp = True + else: + ftime.write(k) + val = ftime.getvalue() + ftime.close() + return val diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/time.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/time.pyi new file mode 100644 index 000000000..26b0e4b08 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/time.pyi @@ -0,0 +1,59 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. +""" + +from __future__ import annotations +from utime import * +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TS_YEAR: int +_TS_MON: int +_TS_MDAY: int +_TS_HOUR: int +_TS_MIN: int +_TS_SEC: int +_TS_WDAY: int +_TS_YDAY: int +_TS_ISDST: int +_WDAY: Incomplete +_MDAY: Incomplete +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def strftime(datefmt, ts): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_OPTA/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/central.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/client.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/core.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/device.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/security.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/server.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/__init__.py new file mode 100644 index 000000000..80790f0da --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/__init__.py @@ -0,0 +1,32 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from ._decoder import CBORDecoder +from ._decoder import load +from ._decoder import loads + +from ._encoder import CBOREncoder +from ._encoder import dump +from ._encoder import dumps diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/__init__.pyi new file mode 100644 index 000000000..0ef59d019 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/__init__.pyi @@ -0,0 +1,2 @@ +from ._decoder import CBORDecoder as CBORDecoder, load as load, loads as loads +from ._encoder import CBOREncoder as CBOREncoder, dump as dump, dumps as dumps diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_decoder.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_decoder.py new file mode 100644 index 000000000..8434aec26 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_decoder.py @@ -0,0 +1,254 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + + +break_marker = object() + + +class CBORSimpleValue(object): + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + def __init__(self, value): + if value < 0 or value > 255: + raise TypeError("simple value too big") + self.value = value + + def __eq__(self, other): + if isinstance(other, CBORSimpleValue): + return self.value == other.value + elif isinstance(other, int): + return self.value == other + return NotImplemented + + def __repr__(self): + return "CBORSimpleValue({self.value})".format(self=self) + + +def decode_uint(decoder, subtype, allow_indefinite=False): + # Major tag 0 + if subtype < 24: + return subtype + elif subtype == 24: + return struct.unpack(">B", decoder.read(1))[0] + elif subtype == 25: + return struct.unpack(">H", decoder.read(2))[0] + elif subtype == 26: + return struct.unpack(">L", decoder.read(4))[0] + elif subtype == 27: + return struct.unpack(">Q", decoder.read(8))[0] + elif subtype == 31 and allow_indefinite: + return None + else: + raise CBORDecodeError("unknown unsigned integer subtype 0x%x" % subtype) + + +def decode_negint(decoder, subtype): + # Major tag 1 + uint = decode_uint(decoder, subtype) + return -uint - 1 + + +def decode_bytestring(decoder, subtype): + # Major tag 2 + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + buf = bytearray() + while True: + initial_byte = decoder.read(1)[0] + if initial_byte == 255: + return buf + else: + length = decode_uint(decoder, initial_byte & 31) + value = decoder.read(length) + buf.extend(value) + else: + return decoder.read(length) + + +def decode_string(decoder, subtype): + # Major tag 3 + return decode_bytestring(decoder, subtype).decode("utf-8") + + +def decode_array(decoder, subtype): + # Major tag 4 + items = [] + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + value = decoder.decode() + if value is break_marker: + break + else: + items.append(value) + else: + for _ in range(length): + item = decoder.decode() + items.append(item) + return items + + +def decode_map(decoder, subtype): + # Major tag 5 + dictionary = {} + length = decode_uint(decoder, subtype, allow_indefinite=True) + if length is None: + # Indefinite length + while True: + key = decoder.decode() + if key is break_marker: + break + else: + value = decoder.decode() + dictionary[key] = value + else: + for _ in range(length): + key = decoder.decode() + value = decoder.decode() + dictionary[key] = value + + return dictionary + + +def decode_special(decoder, subtype): + # Simple value + if subtype < 20: + return CBORSimpleValue(subtype) + + # Major tag 7 + return special_decoders[subtype](decoder) + + +def decode_simple_value(decoder): + return CBORSimpleValue(struct.unpack(">B", decoder.read(1))[0]) + + +def decode_float16(decoder): + decoder.read(2) + raise NotImplementedError # no float16 unpack function + + +def decode_float32(decoder): + return struct.unpack(">f", decoder.read(4))[0] + + +def decode_float64(decoder): + return struct.unpack(">d", decoder.read(8))[0] + + +major_decoders = { + 0: decode_uint, + 1: decode_negint, + 2: decode_bytestring, + 3: decode_string, + 4: decode_array, + 5: decode_map, + 7: decode_special, +} + +special_decoders = { + 20: lambda self: False, + 21: lambda self: True, + 22: lambda self: None, + # 23 is undefined + 24: decode_simple_value, + 25: decode_float16, + 26: decode_float32, + 27: decode_float64, + 31: lambda self: break_marker, +} + + +class CBORDecoder(object): + """ + Deserializes a CBOR encoded byte stream. + """ + + def __init__(self, fp): + self.fp = fp + + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + data = self.fp.read(amount) + if len(data) < amount: + raise CBORDecodeError("premature end of stream (expected to read {} bytes, got {} instead)".format(amount, len(data))) + + return data + + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + try: + initial_byte = self.fp.read(1)[0] + major_type = initial_byte >> 5 + subtype = initial_byte & 31 + except Exception as e: + raise CBORDecodeError("error reading major type at index {}: {}".format(self.fp.tell(), e)) + + decoder = major_decoders[major_type] + try: + return decoder(self, subtype) + except CBORDecodeError: + raise + except Exception as e: + raise CBORDecodeError("error decoding value {}".format(e)) # tell doesn't work on micropython at the moment + + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + fp = io.BytesIO(payload) + return CBORDecoder(fp, **kwargs).decode() + + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + return CBORDecoder(fp, **kwargs).decode() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_decoder.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_decoder.pyi new file mode 100644 index 000000000..d4daffe85 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_decoder.pyi @@ -0,0 +1,66 @@ +from _typeshed import Incomplete + +class CBORDecodeError(Exception): + """Raised when an error occurs deserializing a CBOR datastream.""" + +break_marker: Incomplete + +class CBORSimpleValue: + """ + Represents a CBOR "simple value". + :param int value: the value (0-255) + """ + + value: Incomplete + def __init__(self, value) -> None: ... + def __eq__(self, other): ... + def __repr__(self) -> str: ... + +def decode_uint(decoder, subtype, allow_indefinite: bool = False): ... +def decode_negint(decoder, subtype): ... +def decode_bytestring(decoder, subtype): ... +def decode_string(decoder, subtype): ... +def decode_array(decoder, subtype): ... +def decode_map(decoder, subtype): ... +def decode_special(decoder, subtype): ... +def decode_simple_value(decoder): ... +def decode_float16(decoder) -> None: ... +def decode_float32(decoder): ... +def decode_float64(decoder): ... + +major_decoders: Incomplete +special_decoders: Incomplete + +class CBORDecoder: + """ + Deserializes a CBOR encoded byte stream. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def read(self, amount): + """ + Read bytes from the data stream. + :param int amount: the number of bytes to read + """ + def decode(self): + """ + Decode the next value from the stream. + :raises CBORDecodeError: if there is any problem decoding the stream + """ + +def loads(payload, **kwargs): + """ + Deserialize an object from a bytestring. + :param bytes payload: the bytestring to serialize + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ + +def load(fp, **kwargs): + """ + Deserialize an object from an open file. + :param fp: the input file (any file-like object) + :param kwargs: keyword arguments passed to :class:`~.CBORDecoder` + :return: the deserialized object + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_encoder.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_encoder.py new file mode 100644 index 000000000..fe8715468 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_encoder.py @@ -0,0 +1,182 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import io +import struct + + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + + +def encode_length(major_tag, length): + if length < 24: + return struct.pack(">B", major_tag | length) + elif length < 256: + return struct.pack(">BB", major_tag | 24, length) + elif length < 65536: + return struct.pack(">BH", major_tag | 25, length) + elif length < 4294967296: + return struct.pack(">BL", major_tag | 26, length) + else: + return struct.pack(">BQ", major_tag | 27, length) + + +def encode_semantic(encoder, tag, value): + encoder.write(encode_length(0xC0, tag)) + encoder.encode(value) + + +def encode_float(encoder, value): + # Handle special values efficiently + import math + + if math.isnan(value): + encoder.write(b"\xf9\x7e\x00") + elif math.isinf(value): + encoder.write(b"\xf9\x7c\x00" if value > 0 else b"\xf9\xfc\x00") + else: + encoder.write(struct.pack(">Bd", 0xFB, value)) + + +def encode_int(encoder, value): + # Big integers (2 ** 64 and over) + if value >= 18446744073709551616 or value < -18446744073709551616: + if value >= 0: + major_type = 0x02 + else: + major_type = 0x03 + value = -value - 1 + + values = [] + while value > 0: + value, remainder = divmod(value, 256) + values.insert(0, remainder) + + payload = bytes(values) + encode_semantic(encoder, major_type, payload) + elif value >= 0: + encoder.write(encode_length(0, value)) + else: + encoder.write(encode_length(0x20, abs(value) - 1)) + + +def encode_bytestring(encoder, value): + encoder.write(encode_length(0x40, len(value)) + value) + + +def encode_bytearray(encoder, value): + encode_bytestring(encoder, bytes(value)) + + +def encode_string(encoder, value): + encoded = value.encode("utf-8") + encoder.write(encode_length(0x60, len(encoded)) + encoded) + + +def encode_map(encoder, value): + encoder.write(encode_length(0xA0, len(value))) + for key, val in value.items(): + encoder.encode(key) + encoder.encode(val) + + +def encode_array(encoder, value): + encoder.write(encode_length(0x80, len(value))) + for item in value: + encoder.encode(item) + + +def encode_boolean(encoder, value): + encoder.write(b"\xf5" if value else b"\xf4") + + +def encode_none(encoder, value): + encoder.write(b"\xf6") + + +cbor_encoders = { # supported data types and the encoder to use. + bytes: encode_bytestring, + bytearray: encode_bytearray, + str: encode_string, + int: encode_int, + float: encode_float, + bool: encode_boolean, + type(None): encode_none, + list: encode_array, + dict: encode_map, +} + + +class CBOREncoder(object): + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + def __init__(self, fp): + self.fp = fp + + def _find_encoder(self, obj): + return cbor_encoders[type(obj)] + + def write(self, data): + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + self.fp.write(data) + + def encode(self, obj): + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + encoder = self._find_encoder(obj) + if not encoder: + raise CBOREncodeError("cannot serialize type %s" % type(obj)) + encoder(self, obj) + + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + fp = io.BytesIO() + dump(obj, fp, **kwargs) + return fp.getvalue() + + +def dump(obj, fp, **kwargs): + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ + CBOREncoder(fp, **kwargs).encode(obj) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_encoder.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_encoder.pyi new file mode 100644 index 000000000..8cd761686 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cbor2/_encoder.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete + +class CBOREncodeError(Exception): + """Raised when an error occurs while serializing an object into a CBOR datastream.""" + +def encode_length(major_tag, length): ... +def encode_semantic(encoder, tag, value) -> None: ... +def encode_float(encoder, value) -> None: ... +def encode_int(encoder, value) -> None: ... +def encode_bytestring(encoder, value) -> None: ... +def encode_bytearray(encoder, value) -> None: ... +def encode_string(encoder, value) -> None: ... +def encode_map(encoder, value) -> None: ... +def encode_array(encoder, value) -> None: ... +def encode_boolean(encoder, value) -> None: ... +def encode_none(encoder, value) -> None: ... + +cbor_encoders: Incomplete + +class CBOREncoder: + """ + Serializes objects to a byte stream using Concise Binary Object Representation. + """ + + fp: Incomplete + def __init__(self, fp) -> None: ... + def _find_encoder(self, obj): ... + def write(self, data) -> None: + """ + Write bytes to the data stream. + :param data: the bytes to write + """ + def encode(self, obj) -> None: + """ + Encode the given object using CBOR. + :param obj: the object to encode + """ + +def dumps(obj, **kwargs): + """ + Serialize an object to a bytestring. + :param obj: the object to serialize + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + :return: the serialized output + :rtype: bytes + """ + +def dump(obj, fp, **kwargs) -> None: + """ + Serialize an object to a file. + :param obj: the object to serialize + :param fp: a file-like object + :param kwargs: keyword arguments passed to :class:`~.CBOREncoder` + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cmwx1.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cmwx1.py new file mode 100644 index 000000000..3616db5a7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cmwx1.py @@ -0,0 +1,357 @@ +# This file is part of the cmwx1 module. +# +# Copyright (c) 2013-2021 Ibrahim Abdelkader +# Copyright (c) 2013-2021 Sebastian Romero +# Copyright (c) 2021 Arduino SA +# +# This work is licensed under the MIT license, see the file LICENSE for details. +# +# CMWX1ZZABZ-093 driver for Arduino boards. +# Note this module runs a stock or a custom Arduino firmware. + +from time import sleep_ms +from time import ticks_ms +from machine import UART +from machine import Pin +from micropython import const + + +class LoraError(Exception): + pass + + +class LoraErrorTimeout(LoraError): + pass + + +class LoraErrorParam(LoraError): + pass + + +class LoraErrorBusy(LoraError): + pass + + +class LoraErrorOverflow(LoraError): + pass + + +class LoraErrorNoNetwork(LoraError): + pass + + +class LoraErrorRX(LoraError): + pass + + +class LoraErrorUnknown(LoraError): + pass + + +class Lora: + MODE_ABP = 0 + MODE_OTAA = 1 + + CLASS_A = "A" + CLASS_B = "B" + CLASS_C = "C" + + BAND_AS923 = 0 + BAND_AU915 = 1 + BAND_EU868 = 5 + BAND_KR920 = 6 + BAND_IN865 = 7 + BAND_US915 = 8 + BAND_US915_HYBRID = 9 + + RF_MODE_RFO = 0 + RF_MODE_PABOOST = 1 + + LoraErrors = { + "": LoraErrorTimeout, # empty buffer + "+ERR": LoraError, + "+ERR_PARAM": LoraErrorParam, + "+ERR_BUSY": LoraErrorBusy, + "+ERR_PARAM_OVERFLOW": LoraErrorOverflow, + "+ERR_NO_NETWORK": LoraErrorNoNetwork, + "+ERR_RX": LoraErrorRX, + "+ERR_UNKNOWN": LoraErrorUnknown, + } + + def __init__( + self, + uart=None, + rst_pin=None, + boot_pin=None, + band=BAND_EU868, # noqa + poll_ms=300000, + debug=False, + ): + self.debug = debug + self.uart = uart + self.rst_pin = rst_pin + self.boot_pin = boot_pin + self.band = band + self.poll_ms = poll_ms + self.last_poll_ms = ticks_ms() + + self.init_modem() + + # Reset module + self.boot_pin.value(0) + self.rst_pin.value(1) + sleep_ms(200) + self.rst_pin.value(0) + sleep_ms(200) + self.rst_pin.value(1) + + # Restart module + self.restart() + + def init_modem(self): + # Arduino Portenta H7 Pin Configuration + if not self.rst_pin: + self.rst_pin = Pin("PC6", Pin.OUT_PP, Pin.PULL_UP, value=1) + if not self.boot_pin: + self.boot_pin = Pin("PG7", Pin.OUT_PP, Pin.PULL_DOWN, value=0) + if not self.uart: + self.uart = UART(8, 19200) + # self.uart = UART(1, 19200) # Use external module + self.uart.init(19200, bits=8, parity=None, stop=2, timeout=250, timeout_char=100) + + def debug_print(self, data): + if self.debug: + print(data) + + def is_arduino_firmware(self): + return "ARD-078" in self.fw_version + + def configure_class(self, _class): + self.send_command("+CLASS=", _class) + + def configure_band(self, band): + self.send_command("+BAND=", band) + if band == self.BAND_EU868 and self.is_arduino_firmware(): + self.send_command("+DUTYCYCLE=", 1) + return True + + def set_baudrate(self, baudrate): + self.send_command("+UART=", baudrate) + + def set_autobaud(self, timeout=10000): + start = ticks_ms() + while (ticks_ms() - start) < timeout: + if self.send_command("", timeout=200, raise_error=False) == "+OK": + sleep_ms(200) + while self.uart.any(): + self.uart.readchar() + return True + return False + + def get_fw_version(self): + dev = self.send_command("+DEV?") + fw_ver = self.send_command("+VER?") + return dev + " " + fw_ver + + def get_device_eui(self): + return self.send_command("+DEVEUI?") + + def factory_default(self): + self.send_command("+FACNEW") + + def restart(self): + if self.set_autobaud() is False: + raise (LoraError("Failed to set autobaud")) + + # Different delimiter as REBOOT response EVENT doesn't end with '\r'. + if self.send_command("+REBOOT", delimiter="+EVENT=0,0", timeout=10000) != "+EVENT=0,0": + raise (LoraError("Failed to reboot module")) + sleep_ms(1000) + self.fw_version = self.get_fw_version() + self.configure_band(self.band) + + def set_rf_power(self, mode, power): + self.send_command("+RFPOWER=", mode, ",", power) + + def set_port(self, port): + self.send_command("+PORT=", port) + + def set_public_network(self, enable): + self.send_command("+NWK=", int(enable)) + + def sleep(self, enable): + self.send_command("+SLEEP=", int(enable)) + + def format(self, hexMode): + self.send_command("+DFORMAT=", int(hexMode)) + + def set_datarate(self, dr): + self.send_command("+DR=", dr) + + def get_datarate(self): + return int(self.send_command("+DR?")) + + def set_adr(self, adr): + self.send_command("+ADR=", int(adr)) + + def get_adr(self): + return int(self.send_command("+ADR?")) + + def get_devaddr(self): + return self.send_command("+DEVADDR?") + + def get_nwk_skey(self): + return self.send_command("+NWKSKEY?") + + def get_appskey(self): + return self.send_command("+APPSKEY?") + + def get_rx2dr(self): + return int(self.send_command("+RX2DR?")) + + def set_rx2dr(self, dr): + self.send_command("+RX2DR=", dr) + + def get_ex2freq(self): + return int(self.send_command("+RX2FQ?")) + + def set_rx2freq(self, freq): + self.send_command("+RX2FQ=", freq) + + def set_fcu(self, fcu): + self.send_command("+FCU=", fcu) + + def get_fcu(self): + return int(self.send_command("+FCU?")) + + def set_fcd(self, fcd): + self.send_command("+FCD=", fcd) + + def get_fcd(self): + return int(self.send_command("+FCD?")) + + def change_mode(self, mode): + self.send_command("+MODE=", mode) + + def join(self, timeout_ms): + if self.send_command("+JOIN", timeout=timeout_ms) != "+ACK": + return False + response = self.receive("\r", timeout=timeout_ms) + return response == "+EVENT=1,1" + + def get_join_status(self): + return int(self.send_command("+NJS?")) == 1 + + def get_max_size(self): + if self.is_arduino_firmware(): + return 64 + return int(self.send_command("+MSIZE?", timeout=2000)) + + def poll(self): + if (ticks_ms() - self.last_poll_ms) > self.poll_ms: + self.last_poll_ms = ticks_ms() + # Triggers a fake write + self.send_data("\0", True) + + def send_data(self, buff, confirmed=True): + max_len = self.get_max_size() + if len(buff) > max_len: + raise (LoraError("Packet exceeds max length")) + if self.send_command("+CTX " if confirmed else "+UTX ", len(buff), data=buff) != "+OK": + return False + if confirmed: + response = self.receive("\r", timeout=10000) + return response == "+ACK" + return True + + def receive_data(self, timeout=1000): + response = self.receive("\r", timeout=timeout) + if response.startswith("+RECV"): + params = response.split("=")[1].split(",") + port = params[0] + length = int(params[1]) + dummy_data_length = 2 # Data starts with \n\n sequence + data = self.receive(max_bytes=length + dummy_data_length, timeout=timeout)[dummy_data_length:] + return {"port": port, "data": data} + + def receive(self, delimiter=None, max_bytes=None, timeout=1000): + buf = [] + start = ticks_ms() + while (ticks_ms() - start) < timeout: + while self.uart.any(): + buf += chr(self.uart.readchar()) + + if max_bytes and len(buf) == max_bytes: + data = "".join(buf) + self.debug_print(data) + return data + if len(buf) and delimiter is not None: + data = "".join(buf) + trimmed = data[0:-1] if data[-1] == "\r" else data + + if isinstance(delimiter, str) and len(delimiter) == 1 and buf[-1] == delimiter: + self.debug_print(trimmed) + return trimmed + if isinstance(delimiter, str) and trimmed == delimiter: + self.debug_print(trimmed) + return trimmed + if isinstance(delimiter, list) and trimmed in delimiter: + self.debug_print(trimmed) + return trimmed + + data = "".join(buf) + self.debug_print(data) + return data[0:-1] if len(data) != 0 and data[-1] == "\r" else data + + def available(self): + return self.uart.any() + + def join_OTAA(self, appEui, appKey, devEui=None, timeout=60000): + self.change_mode(self.MODE_OTAA) + self.send_command("+APPEUI=", appEui) + self.send_command("+APPKEY=", appKey) + if devEui: + self.send_command("+DEVEUI=", devEui) + network_joined = self.join(timeout) + # This delay was in MKRWAN.h + # delay(1000); + return network_joined + + def join_ABP(self, nwkId, devAddr, nwkSKey, appSKey, timeout=60000): + self.change_mode(self.MODE_ABP) + # Commented in MKRWAN.h + # self.send_command("+IDNWK=", nwkId) + self.send_command("+DEVADDR=", devAddr) + self.send_command("+NWKSKEY=", nwkSKey) + self.send_command("+APPSKEY=", appSKey) + self.join(timeout) + return self.get_join_status() + + def handle_error(self, command, data): + if not data.startswith("+ERR") and data != "": + return + if data in self.LoraErrors: + raise (self.LoraErrors[data]('Command "%s" has failed!' % command)) + raise (LoraError('Command: "%s" failed with unknown status: "%s"' % (command, data))) + + def send_command(self, cmd, *args, delimiter="\r", data=None, timeout=1000, raise_error=True): + # Write command and args + uart_cmd = "AT" + cmd + "".join([str(x) for x in args]) + "\r" + self.debug_print(uart_cmd) + self.uart.write(uart_cmd) + + # Attach raw data + if data: + self.debug_print(data) + self.uart.write(data) + + # Read status and value (if any) + response = self.receive(delimiter, timeout=timeout) + + # Error handling + if raise_error: + self.handle_error(cmd, response) + + if cmd.endswith("?"): + return response.split("=")[1] + return response diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cmwx1.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cmwx1.pyi new file mode 100644 index 000000000..82d9651c4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/cmwx1.pyi @@ -0,0 +1,81 @@ +from _typeshed import Incomplete +from micropython import const as const + +class LoraError(Exception): ... +class LoraErrorTimeout(LoraError): ... +class LoraErrorParam(LoraError): ... +class LoraErrorBusy(LoraError): ... +class LoraErrorOverflow(LoraError): ... +class LoraErrorNoNetwork(LoraError): ... +class LoraErrorRX(LoraError): ... +class LoraErrorUnknown(LoraError): ... + +class Lora: + MODE_ABP: int + MODE_OTAA: int + CLASS_A: str + CLASS_B: str + CLASS_C: str + BAND_AS923: int + BAND_AU915: int + BAND_EU868: int + BAND_KR920: int + BAND_IN865: int + BAND_US915: int + BAND_US915_HYBRID: int + RF_MODE_RFO: int + RF_MODE_PABOOST: int + LoraErrors: Incomplete + debug: Incomplete + uart: Incomplete + rst_pin: Incomplete + boot_pin: Incomplete + band: Incomplete + poll_ms: Incomplete + last_poll_ms: Incomplete + def __init__(self, uart=None, rst_pin=None, boot_pin=None, band=..., poll_ms: int = 300000, debug: bool = False) -> None: ... + def init_modem(self) -> None: ... + def debug_print(self, data) -> None: ... + def is_arduino_firmware(self): ... + def configure_class(self, _class) -> None: ... + def configure_band(self, band): ... + def set_baudrate(self, baudrate) -> None: ... + def set_autobaud(self, timeout: int = 10000): ... + def get_fw_version(self): ... + def get_device_eui(self): ... + def factory_default(self) -> None: ... + fw_version: Incomplete + def restart(self) -> None: ... + def set_rf_power(self, mode, power) -> None: ... + def set_port(self, port) -> None: ... + def set_public_network(self, enable) -> None: ... + def sleep(self, enable) -> None: ... + def format(self, hexMode) -> None: ... + def set_datarate(self, dr) -> None: ... + def get_datarate(self): ... + def set_adr(self, adr) -> None: ... + def get_adr(self): ... + def get_devaddr(self): ... + def get_nwk_skey(self): ... + def get_appskey(self): ... + def get_rx2dr(self): ... + def set_rx2dr(self, dr) -> None: ... + def get_ex2freq(self): ... + def set_rx2freq(self, freq) -> None: ... + def set_fcu(self, fcu) -> None: ... + def get_fcu(self): ... + def set_fcd(self, fcd) -> None: ... + def get_fcd(self): ... + def change_mode(self, mode) -> None: ... + def join(self, timeout_ms): ... + def get_join_status(self): ... + def get_max_size(self): ... + def poll(self) -> None: ... + def send_data(self, buff, confirmed: bool = True): ... + def receive_data(self, timeout: int = 1000): ... + def receive(self, delimiter=None, max_bytes=None, timeout: int = 1000): ... + def available(self): ... + def join_OTAA(self, appEui, appKey, devEui=None, timeout: int = 60000): ... + def join_ABP(self, nwkId, devAddr, nwkSKey, appSKey, timeout: int = 60000): ... + def handle_error(self, command, data) -> None: ... + def send_command(self, cmd, *args, delimiter: str = "\r", data=None, timeout: int = 1000, raise_error: bool = True): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/logging.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/logging.py new file mode 100644 index 000000000..edee407c6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/logging.py @@ -0,0 +1,253 @@ +from micropython import const +import io +import sys +import time + +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 + +_DEFAULT_LEVEL = WARNING + +_level_dict = { + CRITICAL: "CRITICAL", + ERROR: "ERROR", + WARNING: "WARNING", + INFO: "INFO", + DEBUG: "DEBUG", + NOTSET: "NOTSET", +} + +_loggers = {} +_stream = sys.stderr +_default_fmt = "%(levelname)s:%(name)s:%(message)s" +_default_datefmt = "%Y-%m-%d %H:%M:%S" + + +class LogRecord: + def set(self, name, level, message): + self.name = name + self.levelno = level + self.levelname = _level_dict[level] + self.message = message + self.ct = time.time() + self.msecs = int((self.ct - int(self.ct)) * 1000) + self.asctime = None + + +class Handler: + def __init__(self, level=NOTSET): + self.level = level + self.formatter = None + + def close(self): + pass + + def setLevel(self, level): + self.level = level + + def setFormatter(self, formatter): + self.formatter = formatter + + def format(self, record): + return self.formatter.format(record) + + +class StreamHandler(Handler): + def __init__(self, stream=None): + super().__init__() + self.stream = _stream if stream is None else stream + self.terminator = "\n" + + def close(self): + if hasattr(self.stream, "flush"): + self.stream.flush() + + def emit(self, record): + if record.levelno >= self.level: + self.stream.write(self.format(record) + self.terminator) + + +class FileHandler(StreamHandler): + def __init__(self, filename, mode="a", encoding="UTF-8"): + super().__init__(stream=open(filename, mode=mode, encoding=encoding)) + + def close(self): + super().close() + self.stream.close() + + +class Formatter: + def __init__(self, fmt=None, datefmt=None): + self.fmt = _default_fmt if fmt is None else fmt + self.datefmt = _default_datefmt if datefmt is None else datefmt + + def usesTime(self): + return "asctime" in self.fmt + + def formatTime(self, datefmt, record): + if hasattr(time, "strftime"): + return time.strftime(datefmt, time.localtime(record.ct)) + return None + + def format(self, record): + if self.usesTime(): + record.asctime = self.formatTime(self.datefmt, record) + return self.fmt % { + "name": record.name, + "message": record.message, + "msecs": record.msecs, + "asctime": record.asctime, + "levelname": record.levelname, + } + + +class Logger: + def __init__(self, name, level=NOTSET): + self.name = name + self.level = level + self.handlers = [] + self.record = LogRecord() + + def setLevel(self, level): + self.level = level + + def isEnabledFor(self, level): + return level >= self.getEffectiveLevel() + + def getEffectiveLevel(self): + return self.level or getLogger().level or _DEFAULT_LEVEL + + def log(self, level, msg, *args): + if self.isEnabledFor(level): + if args: + if isinstance(args[0], dict): + args = args[0] + msg = msg % args + self.record.set(self.name, level, msg) + handlers = self.handlers + if not handlers: + handlers = getLogger().handlers + for h in handlers: + h.emit(self.record) + + def debug(self, msg, *args): + self.log(DEBUG, msg, *args) + + def info(self, msg, *args): + self.log(INFO, msg, *args) + + def warning(self, msg, *args): + self.log(WARNING, msg, *args) + + def error(self, msg, *args): + self.log(ERROR, msg, *args) + + def critical(self, msg, *args): + self.log(CRITICAL, msg, *args) + + def exception(self, msg, *args, exc_info=True): + self.log(ERROR, msg, *args) + tb = None + if isinstance(exc_info, BaseException): + tb = exc_info + elif hasattr(sys, "exc_info"): + tb = sys.exc_info()[1] + if tb: + buf = io.StringIO() + sys.print_exception(tb, buf) + self.log(ERROR, buf.getvalue()) + + def addHandler(self, handler): + self.handlers.append(handler) + + def hasHandlers(self): + return len(self.handlers) > 0 + + +def getLogger(name=None): + if name is None: + name = "root" + if name not in _loggers: + _loggers[name] = Logger(name) + if name == "root": + basicConfig() + return _loggers[name] + + +def log(level, msg, *args): + getLogger().log(level, msg, *args) + + +def debug(msg, *args): + getLogger().debug(msg, *args) + + +def info(msg, *args): + getLogger().info(msg, *args) + + +def warning(msg, *args): + getLogger().warning(msg, *args) + + +def error(msg, *args): + getLogger().error(msg, *args) + + +def critical(msg, *args): + getLogger().critical(msg, *args) + + +def exception(msg, *args, exc_info=True): + getLogger().exception(msg, *args, exc_info=exc_info) + + +def shutdown(): + for k, logger in _loggers.items(): + for h in logger.handlers: + h.close() + _loggers.pop(logger, None) + + +def addLevelName(level, name): + _level_dict[level] = name + + +def basicConfig( + filename=None, + filemode="a", + format=None, + datefmt=None, + level=WARNING, + stream=None, + encoding="UTF-8", + force=False, +): + if "root" not in _loggers: + _loggers["root"] = Logger("root") + + logger = _loggers["root"] + + if force or not logger.handlers: + for h in logger.handlers: + h.close() + logger.handlers = [] + + if filename is None: + handler = StreamHandler(stream) + else: + handler = FileHandler(filename, filemode, encoding) + + handler.setLevel(level) + handler.setFormatter(Formatter(format, datefmt)) + + logger.setLevel(level) + logger.addHandler(handler) + + +if hasattr(sys, "atexit"): + sys.atexit(shutdown) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/logging.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/logging.pyi new file mode 100644 index 000000000..856bcccf7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/logging.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete +from micropython import const as const + +CRITICAL: int +ERROR: int +WARNING: int +INFO: int +DEBUG: int +NOTSET: int +_DEFAULT_LEVEL = WARNING +_level_dict: Incomplete +_loggers: Incomplete +_stream: Incomplete +_default_fmt: str +_default_datefmt: str + +class LogRecord: + name: Incomplete + levelno: Incomplete + levelname: Incomplete + message: Incomplete + ct: Incomplete + msecs: Incomplete + asctime: Incomplete + def set(self, name, level, message) -> None: ... + +class Handler: + level: Incomplete + formatter: Incomplete + def __init__(self, level=...) -> None: ... + def close(self) -> None: ... + def setLevel(self, level) -> None: ... + def setFormatter(self, formatter) -> None: ... + def format(self, record): ... + +class StreamHandler(Handler): + stream: Incomplete + terminator: str + def __init__(self, stream=None) -> None: ... + def close(self) -> None: ... + def emit(self, record) -> None: ... + +class FileHandler(StreamHandler): + def __init__(self, filename, mode: str = "a", encoding: str = "UTF-8") -> None: ... + def close(self) -> None: ... + +class Formatter: + fmt: Incomplete + datefmt: Incomplete + def __init__(self, fmt=None, datefmt=None) -> None: ... + def usesTime(self): ... + def formatTime(self, datefmt, record): ... + def format(self, record): ... + +class Logger: + name: Incomplete + level: Incomplete + handlers: Incomplete + record: Incomplete + def __init__(self, name, level=...) -> None: ... + def setLevel(self, level) -> None: ... + def isEnabledFor(self, level): ... + def getEffectiveLevel(self): ... + def log(self, level, msg, *args) -> None: ... + def debug(self, msg, *args) -> None: ... + def info(self, msg, *args) -> None: ... + def warning(self, msg, *args) -> None: ... + def error(self, msg, *args) -> None: ... + def critical(self, msg, *args) -> None: ... + def exception(self, msg, *args, exc_info: bool = True) -> None: ... + def addHandler(self, handler) -> None: ... + def hasHandlers(self): ... + +def getLogger(name=None): ... +def log(level, msg, *args) -> None: ... +def debug(msg, *args) -> None: ... +def info(msg, *args) -> None: ... +def warning(msg, *args) -> None: ... +def error(msg, *args) -> None: ... +def critical(msg, *args) -> None: ... +def exception(msg, *args, exc_info: bool = True) -> None: ... +def shutdown() -> None: ... +def addLevelName(level, name) -> None: ... +def basicConfig( + filename=None, filemode: str = "a", format=None, datefmt=None, level=..., stream=None, encoding: str = "UTF-8", force: bool = False +) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/modules.json new file mode 100644 index 000000000..53c3a51d9 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/modules.json @@ -0,0 +1,156 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "ARDUINO_PORTENTA_H7", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "cbor2/__init__.py", + "module": "__init__" + }, + { + "file": "cbor2/_decoder.py", + "module": "_decoder" + }, + { + "file": "cbor2/_encoder.py", + "module": "_encoder" + }, + { + "file": "cmwx1.py", + "module": "cmwx1" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "logging.py", + "module": "logging" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "msgpack.py", + "module": "msgpack" + }, + { + "file": "msgpackrpc.py", + "module": "msgpackrpc" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "se05x/__init__.py", + "module": "__init__" + }, + { + "file": "se05x/iso7816.py", + "module": "iso7816" + }, + { + "file": "se05x/se05x.py", + "module": "se05x" + }, + { + "file": "senml/__init__.py", + "module": "__init__" + }, + { + "file": "senml/senml_base.py", + "module": "senml_base" + }, + { + "file": "senml/senml_pack.py", + "module": "senml_pack" + }, + { + "file": "senml/senml_record.py", + "module": "senml_record" + }, + { + "file": "senml/senml_unit.py", + "module": "senml_unit" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "time.py", + "module": "time" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpack.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpack.py new file mode 100644 index 000000000..3f1f2683c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpack.py @@ -0,0 +1,860 @@ +# u-msgpack-python v2.8.0 - v at sergeev.io +# https://github.com/vsergeev/u-msgpack-python +# +# u-msgpack-python is a lightweight MessagePack serializer and deserializer +# module, compatible with both Python 2 and 3, as well CPython and PyPy +# implementations of Python. u-msgpack-python is fully compliant with the +# latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +# particular, it supports the new binary, UTF-8 string, and application ext +# types. +# +# MIT License +# +# Copyright (c) 2013-2023 vsergeev / Ivan (Vanya) A. Sergeev +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +""" +u-msgpack-python v2.8.0 - v at sergeev.io +https://github.com/vsergeev/u-msgpack-python + +u-msgpack-python is a lightweight MessagePack serializer and deserializer +module, compatible with both Python 2 and 3, as well CPython and PyPy +implementations of Python. u-msgpack-python is fully compliant with the +latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +particular, it supports the new binary, UTF-8 string, and application ext +types. + +License: MIT +""" + +import struct +import collections +import sys +import io + +__version__ = "2.8.0" +"Module version string" + +version = (2, 8, 0) +"Module version tuple" + + +############################################################################## +# Ext Class +############################################################################## + + +# Extension type for application-defined types and data +class Ext(object): + """ + The Ext class facilitates creating a serializable extension object to store + an application-defined type and data byte array. + """ + + def __init__(self, type, data): + """ + Construct a new Ext object. + + Args: + type (int): application-defined type integer + data (bytes): application-defined data byte array + + Raises: + TypeError: + Type is not an integer. + ValueError: + Type is out of range of -128 to 127. + TypeError: + Data is not type 'bytes' (Python 3) or not type 'str' (Python 2). + + Example: + >>> foo = umsgpack.Ext(5, b"\\x01\\x02\\x03") + >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) + '\\x82\\xa7awesome\\xc3\\xadspecial stuff\\xc7\\x03\\x05\\x01\\x02\\x03' + >>> bar = umsgpack.unpackb(_) + >>> print(bar["special stuff"]) + Ext Object (Type: 5, Data: 01 02 03) + """ + # Check type is type int and in range + if not isinstance(type, int): + raise TypeError("ext type is not type integer") + elif not (-(2**7) <= type <= 2**7 - 1): + raise ValueError("ext type value {:d} is out of range (-128 to 127)".format(type)) + # Check data is type bytes or str + elif sys.version_info[0] == 3 and not isinstance(data, bytes): + raise TypeError("ext data is not type 'bytes'") + elif sys.version_info[0] == 2 and not isinstance(data, str): + raise TypeError("ext data is not type 'str'") + + self.type = type + self.data = data + + def __eq__(self, other): + """ + Compare this Ext object with another for equality. + """ + return isinstance(other, self.__class__) and self.type == other.type and self.data == other.data + + def __ne__(self, other): + """ + Compare this Ext object with another for inequality. + """ + return not self.__eq__(other) + + def __str__(self): + """ + String representation of this Ext object. + """ + s = "Ext Object (Type: {:d}, Data: ".format(self.type) + s += " ".join(["0x{:02x}".format(ord(self.data[i : i + 1])) for i in range(min(len(self.data), 8))]) + if len(self.data) > 8: + s += " ..." + s += ")" + return s + + def __hash__(self): + """ + Provide a hash of this Ext object. + """ + return hash((self.type, self.data)) + + +class InvalidString(bytes): + """Subclass of bytes to hold invalid UTF-8 strings.""" + + +############################################################################## +# Ext Serializable Decorator +############################################################################## + +_ext_class_to_type = {} +_ext_type_to_class = {} + + +def ext_serializable(ext_type): + """ + Return a decorator to register a class for automatic packing and unpacking + with the specified Ext type code. The application class should implement a + `packb()` method that returns serialized bytes, and an `unpackb()` class + method or static method that accepts serialized bytes and returns an + instance of the application class. + + Args: + ext_type (int): application-defined Ext type code + + Raises: + TypeError: + Ext type is not an integer. + ValueError: + Ext type is out of range of -128 to 127. + ValueError: + Ext type or class already registered. + """ + + def wrapper(cls): + if not isinstance(ext_type, int): + raise TypeError("Ext type is not type integer") + elif not (-(2**7) <= ext_type <= 2**7 - 1): + raise ValueError("Ext type value {:d} is out of range of -128 to 127".format(ext_type)) + elif ext_type in _ext_type_to_class: + raise ValueError("Ext type {:d} already registered with class {:s}".format(ext_type, repr(_ext_type_to_class[ext_type]))) + elif cls in _ext_class_to_type: + raise ValueError("Class {:s} already registered with Ext type {:d}".format(repr(cls), ext_type)) + + _ext_type_to_class[ext_type] = cls + _ext_class_to_type[cls] = ext_type + + return cls + + return wrapper + + +############################################################################## +# Exceptions +############################################################################## + + +# Base Exception classes +class PackException(Exception): + "Base class for exceptions encountered during packing." + + +class UnpackException(Exception): + "Base class for exceptions encountered during unpacking." + + +# Packing error +class UnsupportedTypeException(PackException): + "Object type not supported for packing." + + +# Unpacking error +class InsufficientDataException(UnpackException): + "Insufficient data to unpack the serialized object." + + +class InvalidStringException(UnpackException): + "Invalid UTF-8 string encountered during unpacking." + + +class UnsupportedTimestampException(UnpackException): + "Unsupported timestamp format encountered during unpacking." + + +class ReservedCodeException(UnpackException): + "Reserved code encountered during unpacking." + + +class UnhashableKeyException(UnpackException): + """ + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + """ + + +class DuplicateKeyException(UnpackException): + "Duplicate key encountered during map unpacking." + + +############################################################################## +# Packing +############################################################################## + +# You may notice struct.pack("B", obj) instead of the simpler chr(obj) in the +# code below. This is to allow for seamless Python 2 and 3 compatibility, as +# chr(obj) has a str return type instead of bytes in Python 3, and +# struct.pack(...) has the right return type in both versions. + + +def _pack_integer(obj, fp, options): + if obj < 0: + if obj >= -32: + fp.write(struct.pack("b", obj)) + elif obj >= -(2 ** (8 - 1)): + fp.write(b"\xd0" + struct.pack("b", obj)) + elif obj >= -(2 ** (16 - 1)): + fp.write(b"\xd1" + struct.pack(">h", obj)) + elif obj >= -(2 ** (32 - 1)): + fp.write(b"\xd2" + struct.pack(">i", obj)) + elif obj >= -(2 ** (64 - 1)): + fp.write(b"\xd3" + struct.pack(">q", obj)) + else: + raise UnsupportedTypeException("huge signed int") + else: + if obj < 128: + fp.write(struct.pack("B", obj)) + elif obj < 2**8: + fp.write(b"\xcc" + struct.pack("B", obj)) + elif obj < 2**16: + fp.write(b"\xcd" + struct.pack(">H", obj)) + elif obj < 2**32: + fp.write(b"\xce" + struct.pack(">I", obj)) + elif obj < 2**64: + fp.write(b"\xcf" + struct.pack(">Q", obj)) + else: + raise UnsupportedTypeException("huge unsigned int") + + +def _pack_nil(obj, fp, options): + fp.write(b"\xc0") + + +def _pack_boolean(obj, fp, options): + fp.write(b"\xc3" if obj else b"\xc2") + + +def _pack_float(obj, fp, options): + float_precision = options.get("force_float_precision", "single") + + if float_precision == "double": + fp.write(b"\xcb" + struct.pack(">d", obj)) + elif float_precision == "single": + fp.write(b"\xca" + struct.pack(">f", obj)) + else: + raise ValueError("invalid float precision") + + +def _pack_string(obj, fp, options): + obj = obj.encode("utf-8") + obj_len = len(obj) + if obj_len < 32: + fp.write(struct.pack("B", 0xA0 | obj_len) + obj) + elif obj_len < 2**8: + fp.write(b"\xd9" + struct.pack("B", obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xda" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xdb" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge string") + + +def _pack_binary(obj, fp, options): + obj_len = len(obj) + if obj_len < 2**8: + fp.write(b"\xc4" + struct.pack("B", obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xc5" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xc6" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge binary string") + + +def _pack_oldspec_raw(obj, fp, options): + obj_len = len(obj) + if obj_len < 32: + fp.write(struct.pack("B", 0xA0 | obj_len) + obj) + elif obj_len < 2**16: + fp.write(b"\xda" + struct.pack(">H", obj_len) + obj) + elif obj_len < 2**32: + fp.write(b"\xdb" + struct.pack(">I", obj_len) + obj) + else: + raise UnsupportedTypeException("huge raw string") + + +def _pack_ext(obj, fp, options): + obj_len = len(obj.data) + if obj_len == 1: + fp.write(b"\xd4" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 2: + fp.write(b"\xd5" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 4: + fp.write(b"\xd6" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 8: + fp.write(b"\xd7" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len == 16: + fp.write(b"\xd8" + struct.pack("B", obj.type & 0xFF) + obj.data) + elif obj_len < 2**8: + fp.write(b"\xc7" + struct.pack("BB", obj_len, obj.type & 0xFF) + obj.data) + elif obj_len < 2**16: + fp.write(b"\xc8" + struct.pack(">HB", obj_len, obj.type & 0xFF) + obj.data) + elif obj_len < 2**32: + fp.write(b"\xc9" + struct.pack(">IB", obj_len, obj.type & 0xFF) + obj.data) + else: + raise UnsupportedTypeException("huge ext data") + + +def _pack_array(obj, fp, options): + obj_len = len(obj) + if obj_len < 16: + fp.write(struct.pack("B", 0x90 | obj_len)) + elif obj_len < 2**16: + fp.write(b"\xdc" + struct.pack(">H", obj_len)) + elif obj_len < 2**32: + fp.write(b"\xdd" + struct.pack(">I", obj_len)) + else: + raise UnsupportedTypeException("huge array") + + for e in obj: + pack(e, fp, **options) + + +def _pack_map(obj, fp, options): + obj_len = len(obj) + if obj_len < 16: + fp.write(struct.pack("B", 0x80 | obj_len)) + elif obj_len < 2**16: + fp.write(b"\xde" + struct.pack(">H", obj_len)) + elif obj_len < 2**32: + fp.write(b"\xdf" + struct.pack(">I", obj_len)) + else: + raise UnsupportedTypeException("huge array") + + for k, v in obj.items(): + pack(k, fp, **options) + pack(v, fp, **options) + + +# Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type +def pack(obj, fp, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + None + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> f = open('test.bin', 'wb') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + """ + ext_handlers = options.get("ext_handlers") + + if obj is None: + _pack_nil(obj, fp, options) + elif ext_handlers and obj.__class__ in ext_handlers: + _pack_ext(ext_handlers[obj.__class__](obj), fp, options) + elif obj.__class__ in _ext_class_to_type: + try: + _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) + elif isinstance(obj, bool): + _pack_boolean(obj, fp, options) + elif isinstance(obj, int): + _pack_integer(obj, fp, options) + elif isinstance(obj, float): + _pack_float(obj, fp, options) + elif isinstance(obj, str): + _pack_string(obj, fp, options) + elif isinstance(obj, bytes): + _pack_binary(obj, fp, options) + elif isinstance(obj, (list, tuple)): + _pack_array(obj, fp, options) + elif isinstance(obj, dict): + _pack_map(obj, fp, options) + elif isinstance(obj, Ext): + _pack_ext(obj, fp, options) + elif ext_handlers: + # Linear search for superclass + t = next((t for t in ext_handlers.keys() if isinstance(obj, t)), None) + if t: + _pack_ext(ext_handlers[t](obj), fp, options) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + elif _ext_class_to_type: + # Linear search for superclass + t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) + if t: + try: + _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + + +def packb(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + bytes: Serialized MessagePack bytes + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + b'\\x82\\xa7compact\\xc3\\xa6schema\\x00' + """ + fp = io.BytesIO() + pack(obj, fp, **options) + return fp.getvalue() + + +############################################################################# +# Unpacking +############################################################################# + + +def _read_except(fp, n): + if n == 0: + return b"" + + data = fp.read(n) + if len(data) == 0: + raise InsufficientDataException() + + while len(data) < n: + chunk = fp.read(n - len(data)) + if len(chunk) == 0: + raise InsufficientDataException() + + data += chunk + + return data + + +def _unpack_integer(code, fp, options): + if (ord(code) & 0xE0) == 0xE0: + return struct.unpack("b", code)[0] + elif code == b"\xd0": + return struct.unpack("b", _read_except(fp, 1))[0] + elif code == b"\xd1": + return struct.unpack(">h", _read_except(fp, 2))[0] + elif code == b"\xd2": + return struct.unpack(">i", _read_except(fp, 4))[0] + elif code == b"\xd3": + return struct.unpack(">q", _read_except(fp, 8))[0] + elif (ord(code) & 0x80) == 0x00: + return struct.unpack("B", code)[0] + elif code == b"\xcc": + return struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xcd": + return struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xce": + return struct.unpack(">I", _read_except(fp, 4))[0] + elif code == b"\xcf": + return struct.unpack(">Q", _read_except(fp, 8))[0] + raise Exception("logic error, not int: 0x{:02x}".format(ord(code))) + + +def _unpack_reserved(code, fp, options): + if code == b"\xc1": + raise ReservedCodeException("encountered reserved code: 0x{:02x}".format(ord(code))) + raise Exception("logic error, not reserved code: 0x{:02x}".format(ord(code))) + + +def _unpack_nil(code, fp, options): + if code == b"\xc0": + return None + raise Exception("logic error, not nil: 0x{:02x}".format(ord(code))) + + +def _unpack_boolean(code, fp, options): + if code == b"\xc2": + return False + elif code == b"\xc3": + return True + raise Exception("logic error, not boolean: 0x{:02x}".format(ord(code))) + + +def _unpack_float(code, fp, options): + if code == b"\xca": + return struct.unpack(">f", _read_except(fp, 4))[0] + elif code == b"\xcb": + return struct.unpack(">d", _read_except(fp, 8))[0] + raise Exception("logic error, not float: 0x{:02x}".format(ord(code))) + + +def _unpack_string(code, fp, options): + if (ord(code) & 0xE0) == 0xA0: + length = ord(code) & ~0xE0 + elif code == b"\xd9": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xda": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdb": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not string: 0x{:02x}".format(ord(code))) + + data = _read_except(fp, length) + try: + return bytes.decode(data, "utf-8") + except Exception: + if options.get("allow_invalid_utf8", True): + return InvalidString(data) + raise InvalidStringException("unpacked string is invalid utf-8") + + +def _unpack_binary(code, fp, options): + if code == b"\xc4": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xc5": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xc6": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not binary: 0x{:02x}".format(ord(code))) + + return _read_except(fp, length) + + +def _unpack_ext(code, fp, options): + if code == b"\xd4": + length = 1 + elif code == b"\xd5": + length = 2 + elif code == b"\xd6": + length = 4 + elif code == b"\xd7": + length = 8 + elif code == b"\xd8": + length = 16 + elif code == b"\xc7": + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b"\xc8": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xc9": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not ext: 0x{:02x}".format(ord(code))) + + ext_type = struct.unpack("b", _read_except(fp, 1))[0] + ext_data = _read_except(fp, length) + + # Unpack with ext handler, if we have one + ext_handlers = options.get("ext_handlers") + if ext_handlers and ext_type in ext_handlers: + return ext_handlers[ext_type](Ext(ext_type, ext_data)) + + # Unpack with ext classes, if type is registered + if ext_type in _ext_type_to_class: + try: + return _ext_type_to_class[ext_type].unpackb(ext_data) + except AttributeError: + raise NotImplementedError( + "Ext serializable class {:s} is missing implementation of unpackb()".format(repr(_ext_type_to_class[ext_type])) + ) + + return Ext(ext_type, ext_data) + + +def _unpack_array(code, fp, options): + if (ord(code) & 0xF0) == 0x90: + length = ord(code) & ~0xF0 + elif code == b"\xdc": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdd": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not array: 0x{:02x}".format(ord(code))) + + if options.get("use_tuple"): + return tuple((_unpack(fp, options) for i in range(length))) + + return [_unpack(fp, options) for i in range(length)] + + +def _deep_list_to_tuple(obj): + if isinstance(obj, list): + return tuple([_deep_list_to_tuple(e) for e in obj]) + return obj + + +def _unpack_map(code, fp, options): + if (ord(code) & 0xF0) == 0x80: + length = ord(code) & ~0xF0 + elif code == b"\xde": + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b"\xdf": + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not map: 0x{:02x}".format(ord(code))) + + d = {} if not options.get("use_ordered_dict") else collections.OrderedDict() + for _ in range(length): + # Unpack key + k = _unpack(fp, options) + + if isinstance(k, list): + # Attempt to convert list into a hashable tuple + k = _deep_list_to_tuple(k) + try: + hash(k) + except Exception: + raise UnhashableKeyException('encountered unhashable key: "{:s}" ({:s})'.format(str(k), str(type(k)))) + if k in d: + raise DuplicateKeyException('encountered duplicate key: "{:s}" ({:s})'.format(str(k), str(type(k)))) + + # Unpack value + v = _unpack(fp, options) + + try: + d[k] = v + except TypeError: + raise UnhashableKeyException('encountered unhashable key: "{:s}"'.format(str(k))) + return d + + +def _unpack(fp, options): + code = _read_except(fp, 1) + return _unpack_dispatch_table[code](code, fp, options) + + +def unpack(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {'compact': True, 'schema': 0} + """ + return _unpack(fp, options) + + +# For Python 3, expects a bytes object +def unpackb(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s (bytes, bytearray): serialized MessagePack bytes + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + TypeError: + Packed data type is neither 'bytes' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\\x82\\xa7compact\\xc3\\xa6schema\\x00') + {'compact': True, 'schema': 0} + """ + if not isinstance(s, (bytes, bytearray)): + raise TypeError("packed data must be type 'bytes' or 'bytearray'") + return _unpack(io.BytesIO(s), options) + + +############################################################################# +# Module Initialization +############################################################################# + + +def __init(): + global _unpack_dispatch_table + # Build a dispatch table for fast lookup of unpacking function + _unpack_dispatch_table = {} + # Fix uint + for code in range(0, 0x7F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fix map + for code in range(0x80, 0x8F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_map + # Fix array + for code in range(0x90, 0x9F + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_array + # Fix str + for code in range(0xA0, 0xBF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Nil + _unpack_dispatch_table[b"\xc0"] = _unpack_nil + # Reserved + _unpack_dispatch_table[b"\xc1"] = _unpack_reserved + # Boolean + _unpack_dispatch_table[b"\xc2"] = _unpack_boolean + _unpack_dispatch_table[b"\xc3"] = _unpack_boolean + # Bin + for code in range(0xC4, 0xC6 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_binary + # Ext + for code in range(0xC7, 0xC9 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # Float + _unpack_dispatch_table[b"\xca"] = _unpack_float + _unpack_dispatch_table[b"\xcb"] = _unpack_float + # Uint + for code in range(0xCC, 0xCF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Int + for code in range(0xD0, 0xD3 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fixext + for code in range(0xD4, 0xD8 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # String + for code in range(0xD9, 0xDB + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Array + _unpack_dispatch_table[b"\xdc"] = _unpack_array + _unpack_dispatch_table[b"\xdd"] = _unpack_array + # Map + _unpack_dispatch_table[b"\xde"] = _unpack_map + _unpack_dispatch_table[b"\xdf"] = _unpack_map + # Negative fixint + for code in range(0xE0, 0xFF + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + + +__init() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpack.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpack.pyi new file mode 100644 index 000000000..2dec10602 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpack.pyi @@ -0,0 +1,278 @@ +from _typeshed import Incomplete + +__version__: str +version: Incomplete + +class Ext: + """ + The Ext class facilitates creating a serializable extension object to store + an application-defined type and data byte array. + """ + + type: Incomplete + data: Incomplete + def __init__(self, type, data) -> None: + """ + Construct a new Ext object. + + Args: + type (int): application-defined type integer + data (bytes): application-defined data byte array + + Raises: + TypeError: + Type is not an integer. + ValueError: + Type is out of range of -128 to 127. + TypeError: + Data is not type \'bytes\' (Python 3) or not type \'str\' (Python 2). + + Example: + >>> foo = umsgpack.Ext(5, b"\\x01\\x02\\x03") + >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) + \'\\x82\\xa7awesome\\xc3\\xadspecial stuff\\xc7\\x03\\x05\\x01\\x02\\x03\' + >>> bar = umsgpack.unpackb(_) + >>> print(bar["special stuff"]) + Ext Object (Type: 5, Data: 01 02 03) + """ + def __eq__(self, other): + """ + Compare this Ext object with another for equality. + """ + def __ne__(self, other): + """ + Compare this Ext object with another for inequality. + """ + def __str__(self) -> str: + """ + String representation of this Ext object. + """ + def __hash__(self): + """ + Provide a hash of this Ext object. + """ + +class InvalidString(bytes): + """Subclass of bytes to hold invalid UTF-8 strings.""" + +_ext_class_to_type: Incomplete +_ext_type_to_class: Incomplete + +def ext_serializable(ext_type): + """ + Return a decorator to register a class for automatic packing and unpacking + with the specified Ext type code. The application class should implement a + `packb()` method that returns serialized bytes, and an `unpackb()` class + method or static method that accepts serialized bytes and returns an + instance of the application class. + + Args: + ext_type (int): application-defined Ext type code + + Raises: + TypeError: + Ext type is not an integer. + ValueError: + Ext type is out of range of -128 to 127. + ValueError: + Ext type or class already registered. + """ + +class PackException(Exception): + """Base class for exceptions encountered during packing.""" + +class UnpackException(Exception): + """Base class for exceptions encountered during unpacking.""" + +class UnsupportedTypeException(PackException): + """Object type not supported for packing.""" + +class InsufficientDataException(UnpackException): + """Insufficient data to unpack the serialized object.""" + +class InvalidStringException(UnpackException): + """Invalid UTF-8 string encountered during unpacking.""" + +class UnsupportedTimestampException(UnpackException): + """Unsupported timestamp format encountered during unpacking.""" + +class ReservedCodeException(UnpackException): + """Reserved code encountered during unpacking.""" + +class UnhashableKeyException(UnpackException): + """ + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + """ + +class DuplicateKeyException(UnpackException): + """Duplicate key encountered during map unpacking.""" + +def _pack_integer(obj, fp, options) -> None: ... +def _pack_nil(obj, fp, options) -> None: ... +def _pack_boolean(obj, fp, options) -> None: ... +def _pack_float(obj, fp, options) -> None: ... +def _pack_string(obj, fp, options) -> None: ... +def _pack_binary(obj, fp, options) -> None: ... +def _pack_oldspec_raw(obj, fp, options) -> None: ... +def _pack_ext(obj, fp, options) -> None: ... +def _pack_array(obj, fp, options) -> None: ... +def _pack_map(obj, fp, options) -> None: ... +def pack(obj, fp, **options) -> None: + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + None + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> f = open(\'test.bin\', \'wb\') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + """ + +def packb(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats + + Returns: + bytes: Serialized MessagePack bytes + + Raises: + UnsupportedTypeException(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + b\'\\x82\\xa7compact\\xc3\\xa6schema\\x00\' + """ + +def _read_except(fp, n): ... +def _unpack_integer(code, fp, options): ... +def _unpack_reserved(code, fp, options) -> None: ... +def _unpack_nil(code, fp, options) -> None: ... +def _unpack_boolean(code, fp, options): ... +def _unpack_float(code, fp, options): ... +def _unpack_string(code, fp, options): ... +def _unpack_binary(code, fp, options): ... +def _unpack_ext(code, fp, options): ... +def _unpack_array(code, fp, options): ... +def _deep_list_to_tuple(obj): ... +def _unpack_map(code, fp, options): ... +def _unpack(fp, options): ... +def unpack(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {'compact': True, 'schema': 0} + """ + +def unpackb(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s (bytes, bytearray): serialized MessagePack bytes + + Keyword Args: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of dict + (default False) + use_tuple (bool): unpacks arrays into tuples, instead of lists (default + False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + :class:`InvalidString`, for access to the + bytes (default False) + + Returns: + Python object + + Raises: + TypeError: + Packed data type is neither 'bytes' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\\x82\\xa7compact\\xc3\\xa6schema\\x00') + {'compact': True, 'schema': 0} + """ + +def __init() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpackrpc.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpackrpc.py new file mode 100644 index 000000000..e65c32e83 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpackrpc.py @@ -0,0 +1,202 @@ +# This file is part of the msgpack-rpc module. +# Copyright (c) 2023 Arduino SA +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# MessagePack RPC protocol implementation for MicroPython. +# https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md + +import logging +import openamp +import msgpack +from micropython import const +from io import BytesIO +from time import sleep_ms, ticks_ms, ticks_diff + +_MSG_TYPE_REQUEST = 0 +_MSG_TYPE_RESPONSE = 1 +_MSG_TYPE_NOTIFY = 2 + + +def log_level_enabled(level): + return logging.getLogger().isEnabledFor(level) + + +class Future: + def __init__(self, msgid, msgbuf, fname, fargs): + self.msgid = msgid + self.msgbuf = msgbuf + self.fname = fname + self.fargs = fargs + + def join(self, timeout=0): + if log_level_enabled(logging.DEBUG): + logging.debug(f"join {self.fname}()") + + if timeout > 0: + t = ticks_ms() + + while self.msgid not in self.msgbuf: + if timeout > 0 and ticks_diff(ticks_ms(), t) > timeout: + raise OSError(f"Timeout joining function {self.fname}") + sleep_ms(100) + + obj = self.msgbuf.pop(self.msgid) + if obj[2] is not None: + raise (OSError(obj[2])) + + if log_level_enabled(logging.DEBUG): + logging.debug(f"call {self.fname}({self.fargs}) => {obj}") + return obj[3] + + +class MsgPackIO: + def __init__(self): + self.stream = BytesIO() + + def feed(self, data): + offset = self.stream.tell() + self.stream.write(data) + self.stream.seek(offset) + + def readable(self): + if self.stream.read(1): + offset = self.stream.tell() + self.stream.seek(offset - 1) + return True + return False + + def truncate(self): + if self.readable(): + offset = self.stream.tell() + self.stream = BytesIO(self.stream.getvalue()[offset:]) + + def __iter__(self): + return self + + def __next__(self): + offset = self.stream.tell() + try: + obj = msgpack.unpack(self.stream) + self.truncate() + return obj + except Exception: + self.stream.seek(offset) + raise StopIteration + + +class MsgPackRPC: + def __init__(self, streaming=False): + """ + Create a MsgPack RPC object. + streaming: If True, messages can span multiple buffers, otherwise a buffer contains + exactly one full message. Note streaming mode is slower, so it should be disabled + if it's not needed. + """ + self.epts = {} + self.msgid = 0 + self.msgbuf = {} + self.msgio = MsgPackIO() if streaming else None + self.callables = {} + + def _bind_callback(self, src, name): + if log_level_enabled(logging.INFO): + logging.info(f'New service announcement src: {src} name: "{name}"') + self.epts[name] = openamp.Endpoint(name, self._recv_callback, dest=src) + self.epts[name].send(b"\x00") + + def _recv_callback(self, src, data): + if log_level_enabled(logging.DEBUG): + logging.debug(f"Received message on endpoint: {src} data: {bytes(data)}") + + if self.msgio is None: + obj = msgpack.unpackb(data) + self._process_unpacked_obj(obj) + else: + self.msgio.feed(data) + for obj in self.msgio: + self._process_unpacked_obj(obj) + + def _process_unpacked_obj(self, obj): + if obj[0] == _MSG_TYPE_RESPONSE: + self.msgbuf[obj[1]] = obj + elif obj[0] == _MSG_TYPE_REQUEST: + self._dispatch(obj[1], obj[2], obj[-1]) + if log_level_enabled(logging.DEBUG): + logging.debug(f"Unpacked {type(obj)} val: {obj}") + + def _send_msg(self, msgid, msgtype, fname, fargs, **kwargs): + timeout = kwargs.pop("timeout", 1000) + endpoint = kwargs.pop("endpoint", "rpc") + self.epts[endpoint].send(msgpack.packb([msgtype, msgid, fname, fargs]), timeout=timeout) + if msgtype == _MSG_TYPE_REQUEST: + self.msgid += 1 + return Future(msgid, self.msgbuf, fname, fargs) + + def _dispatch(self, msgid, fname, fargs): + retobj = None + error = None + + if fname in self.callables: + retobj = self.callables[fname](*fargs) + else: + error = "Unbound function called %s" % (fname) + + self._send_msg(msgid, _MSG_TYPE_RESPONSE, error, retobj) + + def bind(self, name, obj): + """ + Bind a callable or an object to a name. + name: The name to which the callable or object is bound. + obj: A callable or an object to bind to the name. If an object is passed, all of its + public methods will be bound to their respective qualified names. + """ + if callable(obj): + # Bind a single callable to its name. + self.callables[name] = obj + else: + # Bind all public methods of an object to their respective qualified names. + for k, v in obj.__class__.__dict__.items(): + if callable(v) and not k.startswith("_"): + self.callables[name + "." + k] = getattr(obj, k) + + def start(self, firmware=None, num_channels=2, timeout=3000): + """ + Initializes OpenAMP, loads the remote processor's firmware and starts. + firmware: A path to an elf file stored in the filesystem, or an address to an entry point in flash. + num_channels: The number of channels to wait for the remote processor to + create before starting to communicate with it. + timeout: How long to wait for the remote processor to start, 0 means forever. + """ + # Initialize OpenAMP and set the New Service callback. + openamp.new_service_callback(self._bind_callback) + + # Keep a reference to the remote processor object, to stop the GC from collecting + # it, which would call the finaliser and shut down the remote processor while it's + # still being used. + self.rproc = openamp.RemoteProc(firmware) + self.rproc.start() + + # Wait for remote processor to announce the end points. + t = ticks_ms() + while len(self.epts) != num_channels: + if timeout > 0 and ticks_diff(ticks_ms(), t) > timeout: + raise OSError("timeout waiting for the remote processor to start") + sleep_ms(10) + + # Introduce a brief delay to allow the M4 sufficient time + # to bind remote functions before invoking them. + sleep_ms(100) + + def call(self, fname, *args, **kwargs): + """ + Synchronous call. The client is blocked until the RPC is finished. + """ + return self.call_async(fname, *args, *kwargs).join() + + def call_async(self, fname, *args, **kwargs): + """ + Asynchronous call. The client returns a Future object immediately. + """ + return self._send_msg(self.msgid, _MSG_TYPE_REQUEST, fname, list(args), *kwargs) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpackrpc.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpackrpc.pyi new file mode 100644 index 000000000..25c365b6d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/msgpackrpc.pyi @@ -0,0 +1,68 @@ +from _typeshed import Incomplete +from micropython import const as const + +_MSG_TYPE_REQUEST: int +_MSG_TYPE_RESPONSE: int +_MSG_TYPE_NOTIFY: int + +def log_level_enabled(level): ... + +class Future: + msgid: Incomplete + msgbuf: Incomplete + fname: Incomplete + fargs: Incomplete + def __init__(self, msgid, msgbuf, fname, fargs) -> None: ... + def join(self, timeout: int = 0): ... + +class MsgPackIO: + stream: Incomplete + def __init__(self) -> None: ... + def feed(self, data) -> None: ... + def readable(self): ... + def truncate(self) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class MsgPackRPC: + epts: Incomplete + msgid: int + msgbuf: Incomplete + msgio: Incomplete + callables: Incomplete + def __init__(self, streaming: bool = False) -> None: + """ + Create a MsgPack RPC object. + streaming: If True, messages can span multiple buffers, otherwise a buffer contains + exactly one full message. Note streaming mode is slower, so it should be disabled + if it's not needed. + """ + def _bind_callback(self, src, name) -> None: ... + def _recv_callback(self, src, data) -> None: ... + def _process_unpacked_obj(self, obj) -> None: ... + def _send_msg(self, msgid, msgtype, fname, fargs, **kwargs): ... + def _dispatch(self, msgid, fname, fargs) -> None: ... + def bind(self, name, obj) -> None: + """ + Bind a callable or an object to a name. + name: The name to which the callable or object is bound. + obj: A callable or an object to bind to the name. If an object is passed, all of its + public methods will be bound to their respective qualified names. + """ + rproc: Incomplete + def start(self, firmware=None, num_channels: int = 2, timeout: int = 3000) -> None: + """ + Initializes OpenAMP, loads the remote processor's firmware and starts. + firmware: A path to an elf file stored in the filesystem, or an address to an entry point in flash. + num_channels: The number of channels to wait for the remote processor to + create before starting to communicate with it. + timeout: How long to wait for the remote processor to start, 0 means forever. + """ + def call(self, fname, *args, **kwargs): + """ + Synchronous call. The client is blocked until the RPC is finished. + """ + def call_async(self, fname, *args, **kwargs): + """ + Asynchronous call. The client returns a Future object immediately. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/__init__.py new file mode 100644 index 000000000..c27dc08aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/__init__.py @@ -0,0 +1,22 @@ +from .se05x import SE05X # noqa +from .iso7816 import SmartCard # noqa +from micropython import const + +# Secure Object Types. +EC_KEY = 0x01 +AES_KEY = 0x03 +DES_KEY = 0x04 +HMAC_KEY = 0x05 +BINARY = 0x06 +USERID = 0x07 +CURVE = 0x0B +SIGNATURE = 0x0C +MAC = 0x0D +CIPHER = 0x0E + +# Supported EC curves. +EC_CURVE_NIST_P192 = 0x01 +EC_CURVE_NIST_P224 = 0x02 +EC_CURVE_NIST_P256 = 0x03 +EC_CURVE_NIST_P384 = 0x04 +EC_CURVE_NIST_P521 = 0x05 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/__init__.pyi new file mode 100644 index 000000000..aedcefce8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/__init__.pyi @@ -0,0 +1,19 @@ +from .iso7816 import SmartCard as SmartCard +from .se05x import SE05X as SE05X +from micropython import const as const + +EC_KEY: int +AES_KEY: int +DES_KEY: int +HMAC_KEY: int +BINARY: int +USERID: int +CURVE: int +SIGNATURE: int +MAC: int +CIPHER: int +EC_CURVE_NIST_P192: int +EC_CURVE_NIST_P224: int +EC_CURVE_NIST_P256: int +EC_CURVE_NIST_P384: int +EC_CURVE_NIST_P521: int diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/iso7816.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/iso7816.py new file mode 100644 index 000000000..e8d874a0c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/iso7816.py @@ -0,0 +1,382 @@ +# This file is part of the se05x package. +# Copyright (c) 2024 Arduino SA +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# An implementation of ISO7816-3/4 standards. +import struct +import logging +from micropython import const +from time import sleep + +# PCB bits +_NAD_OFFSET = 0 +_PCB_OFFSET = 1 +_LEN_OFFSET = 2 +_INF_OFFSET = 3 + +# Blocks +_I_BLOCK = 0x00 +_I_BLOCK_N = 6 +_I_BLOCK_M = 5 + +_S_BLOCK = 0xC0 +_S_BLOCK_REQ = 0x3F + +_R_BLOCK = 0x80 +_R_BLOCK_N = 4 +_R_BLOCK_ERR = 0x03 + +# S-Block request/response +_RESYNC_REQ = 0x00 +_IFS_REQ = 0x01 +_ABORT_REQ = 0x02 +_WTX_REQ = 0x03 +_END_SESSION_REQ = 0x05 +_CHIP_RESET_REQ = 0x06 +_GET_ATR_REQ = 0x07 +_SOFT_RESET_REQ = 0x0F + +_CLA_ISO7816 = 0x00 +_INS_GP_SELECT = 0xA4 + +_STATE_IBLK = 0 +_STATE_SBLK = 1 +_STATE_SEND = 2 +_STATE_RECV = 3 +_STATE_WAIT = 4 +_STATE_WWTX = 5 +_STATE_DONE = 6 + + +def log_enabled(level): + return logging.getLogger().isEnabledFor(level) + + +class SmartCard: + def __init__(self, bus, nad, aid): + self.seq = 0 + self.bus = bus + self.sad = nad & 0xF0 + self.dad = nad & 0x0F + self.aid = aid + self.atr = None + + # TODO: Optimize these + self.w_buf = memoryview(bytearray(512)) + self.r_buf = memoryview(bytearray(512)) + self.s_buf = memoryview(bytearray(32)) + self.apdu_buf = memoryview(bytearray(512)) + + self.block_name = {_I_BLOCK: "I-Block", _R_BLOCK: "R-Block", _S_BLOCK: "S-Block"} + self.state_name = { + _STATE_IBLK: "IBLK", + _STATE_SBLK: "SBLK", + _STATE_SEND: "SEND", + _STATE_RECV: "RECV", + _STATE_WAIT: "WAIT", + _STATE_WWTX: "WWTX", + _STATE_DONE: "DONE", + } + self.apdu_status = { + 0x6700: "Wrong length", + 0x6985: "Conditions not satisfied", + 0x6982: "Security status not satisfied", + 0x6A80: "Wrong data", + 0x6984: "Data invalid", + 0x6986: "Command not allowed", + 0x6A82: "File not found", + 0x6A84: "File full", + 0x6D00: "Invalid or not supported instruction code.", + } + + def _block_type(self, pcb): + return _I_BLOCK if pcb & 0x80 == 0 else pcb & 0xC0 + + def _block_size(self, buf): + # NAD, PCB, LEN, INF[LEN], CRC[2] + return 3 + buf[_LEN_OFFSET] + 2 + + def _block_crc16(self, prologue, data, poly=0x8408, crc=0xFFFF): + # Calculate prologue checksum + for i in prologue: + crc ^= i + for bit in range(8): + crc = (crc >> 1) ^ poly if crc & 0x1 else crc >> 1 + + # Calculate data checksum + for i in data: + crc ^= i + for bit in range(8): + crc = (crc >> 1) ^ poly if crc & 0x1 else crc >> 1 + crc ^= 0xFFFF + return ((crc & 0xFF) << 8) | ((crc >> 8) & 0xFF) + + def _block_write(self, buf, delay=0): + size = self._block_size(buf) + self.bus.write(buf[0:size]) + + def _block_print(self, txrx, *args): + if len(args) == 1: + buf = args[0] + nad, pcb, bsize = buf[_NAD_OFFSET : _LEN_OFFSET + 1] + crc = buf[_LEN_OFFSET + bsize + 1] << 8 | buf[_LEN_OFFSET + bsize + 2] + else: + nad, pcb, bsize, crc, buf = args + btype = self._block_type(pcb) + bname = self.block_name[btype] + boffs = _INF_OFFSET if len(args) == 1 else 0 + seq = (pcb >> _I_BLOCK_N) & 1 if btype == _I_BLOCK else (pcb >> _R_BLOCK_N) & 1 + if log_enabled(logging.DEBUG): + logging.debug(f"{'Tx' if txrx else 'Rx'}: {bname} NAD: 0x{nad:X} PCB: 0x{pcb:X} LEN: {bsize} SEQ: {seq} CRC: 0x{crc:X}") + buf_hex = "".join(f"{b:02X}" for b in buf[boffs : boffs + bsize]) + logging.debug(f"RAW: {nad:02X}{pcb:02X}{bsize:02X}{buf_hex}{crc:04X}") + + def _block_new(self, buf, btype, **kwargs): + data = kwargs.get("data", None) + bsize = 0 if data is None else len(data) + buf[_NAD_OFFSET] = self.sad | self.dad + buf[_PCB_OFFSET] = btype + buf[_LEN_OFFSET] = bsize + if btype == _S_BLOCK: + buf[_PCB_OFFSET] |= kwargs["request"] + elif btype == _I_BLOCK: + buf[_PCB_OFFSET] |= self.seq << _I_BLOCK_N + buf[_PCB_OFFSET] |= kwargs["chained"] << _I_BLOCK_M + elif btype == _R_BLOCK: + buf[_PCB_OFFSET] |= self.seq << _R_BLOCK_N + buf[_PCB_OFFSET] |= kwargs["error"] & _R_BLOCK_ERR + if bsize: + buf[_INF_OFFSET : _INF_OFFSET + bsize] = data + # Calculate and set CRC + crc = self._block_crc16(buf[0:_INF_OFFSET], buf[_INF_OFFSET : _INF_OFFSET + bsize]) + buf[_LEN_OFFSET + bsize + 1] = (crc >> 8) & 0xFF + buf[_LEN_OFFSET + bsize + 2] = (crc >> 0) & 0xFF + # Toggle I-Block sequence + if btype == _I_BLOCK: + self.seq = self.seq ^ 1 + return buf + + def _send_block(self, btype, arg, retry=25, backoff=1.2): + r_offs = 0 + w_offs = 0 + retry_delay = 1 / 1000 + next_state = _STATE_SBLK if btype == _S_BLOCK else _STATE_IBLK + + while retry: + if log_enabled(logging.DEBUG): + logging.debug(f"STATE: {self.state_name[next_state]} retry: {retry}") + if next_state == _STATE_SBLK: + next_state = _STATE_SEND + prev_state = _STATE_RECV + block = self._block_new(self.w_buf, _S_BLOCK, request=arg) + elif next_state == _STATE_IBLK: + next_state = _STATE_SEND + prev_state = _STATE_RECV + remain = len(arg) - w_offs + bsize = min(remain, self.atr["IFSC"]) + chained = int(remain > self.atr["IFSC"]) + block = self._block_new(self.w_buf, _I_BLOCK, chained=chained, data=arg[w_offs : w_offs + bsize]) + w_offs += bsize + elif next_state == _STATE_SEND: + try: + self._block_write(block) + next_state = prev_state + if log_enabled(logging.DEBUG): + self._block_print(True, block) + except Exception: + retry -= 1 + elif next_state == _STATE_RECV: + try: + # Read NAD, PCB, LEN, information (if present) and CRC. + nad, pcb, bsize = self.bus.read(self.s_buf[0:3]) + if bsize: + self.bus.read(self.r_buf[r_offs : r_offs + bsize]) + crc = int.from_bytes(self.bus.read(self.s_buf[3:5]), "big") + except Exception: + retry -= 1 + next_state = _STATE_WAIT + prev_state = _STATE_RECV + continue + + # Check NAD and CRC. + exp = self._block_crc16(self.s_buf[0:3], self.r_buf[r_offs : r_offs + bsize]) + if nad != (self.sad >> 4) | (self.dad << 4) or crc != exp: + retry -= 1 + next_state = _STATE_SEND + prev_state = _STATE_RECV + block = self._block_new(self.s_buf, _R_BLOCK, error=1) + continue + + if log_enabled(logging.DEBUG): + self._block_print(False, nad, pcb, bsize, crc, self.r_buf[r_offs : r_offs + bsize]) + + # Process block. + btype = self._block_type(pcb) + if btype == _R_BLOCK: + # Retransmit last block if error, or continue block chain. + next_state = _STATE_SEND if pcb & _R_BLOCK_ERR else _STATE_IBLK + prev_state = _STATE_RECV + continue + + if btype == _I_BLOCK: + # Acknowledge I-Block in block chain with R(N(R)). + if pcb & (1 << _I_BLOCK_M): + next_state = _STATE_SEND + prev_state = _STATE_RECV + block = self._block_new(self.s_buf, _R_BLOCK, error=0) + else: + next_state = _STATE_DONE + # Add current I-Block INF size (could be 0). + r_offs += bsize + continue + + if btype == _S_BLOCK: + if pcb & _S_BLOCK_REQ == _RESYNC_REQ: + # Respond to a resync request. + self.seq = 0 + next_state = _STATE_SEND + prev_state = _STATE_RECV + block = self._block_new(self.s_buf, _S_BLOCK, request=_RESYNC_REQ & 0x20) + elif pcb & _S_BLOCK_REQ == _WTX_REQ: + # Respond to a WTX request. + next_state = _STATE_SEND + prev_state = _STATE_WWTX + wtx_delay = self.r_buf[r_offs] * self.atr["BWT"] / 1000 + block = self._block_new(self.s_buf, _S_BLOCK, request=_WTX_REQ & 0x20) + else: + # Add current S-Block INF size (could be 0). + r_offs += bsize + next_state = _STATE_DONE + continue + elif next_state == _STATE_WWTX: + sleep(wtx_delay) + next_state = _STATE_RECV + elif next_state == _STATE_WAIT: + sleep(retry_delay) + retry_delay *= backoff + next_state = prev_state + elif next_state == _STATE_DONE: + return self.r_buf[0:r_offs] + + if retry == 0: + raise RuntimeError("_send_block failed") + + def send_apdu(self, cla, ins, p1, p2, data=None, le=0): + size = 4 + self.apdu_buf[0] = cla + self.apdu_buf[1] = ins + self.apdu_buf[2] = p1 + self.apdu_buf[3] = p2 + if data is not None: + size = len(data) + self.apdu_buf[4] = size + self.apdu_buf[5 : 5 + size] = data + self.apdu_buf[5 + size] = 0x00 + size += 5 + + # Send APDU in I-Block + resp = self._send_block(_I_BLOCK, self.apdu_buf[0:size]) + + # Check response TPDU status + status = int.from_bytes(resp[-2:], "big") + if status != 0x9000: + raise RuntimeError("APDU Error: " + self.apdu_status.get(status, f"Unknown 0x{status:X}")) + + # Return data bytes, if any, or the status. + if len(resp) == 2: + return status + return resp[2 + (0 if resp[1] <= 0x7F else resp[1] & 0x0F) : -2] + + def reset(self): + self.seq = 0 + atr_raw = self._send_block(_S_BLOCK, _SOFT_RESET_REQ) + if self.atr is None: + self.atr = self._parse_atrs(atr_raw) + if log_enabled(logging.INFO): + self._dump_atrs(self.atr) + # Select applet + self.send_apdu(_CLA_ISO7816, _INS_GP_SELECT, 0x04, 0x00, self.aid, le=True) + + def resync(self): + self._send_block(_S_BLOCK, _RESYNC_REQ) + self.seq = 0 + + def _parse_atrs(self, atr_bytes): + atr = {} + # PVER - 1 byte + atr["PVER"] = atr_bytes[0] + # VID - 5 bytes + atr["VID"] = atr_bytes[1:6].hex().upper() + + # Length of DLLP - 1 byte + dllp_length = atr_bytes[6] + atr["DLLP_LENGTH"] = dllp_length + + # DLLP - Variable length (Decode using struct) + dllp = atr_bytes[7 : 7 + dllp_length] + atr["DLLP"] = dllp.hex().upper() + if dllp_length >= 4: + atr["BWT"], atr["IFSC"] = struct.unpack(">HH", dllp[:4]) + + # PLID - 1 byte + atr["PLID"] = atr_bytes[7 + dllp_length] + # Length of PLP - 1 byte + plp_length = atr_bytes[8 + dllp_length] + atr["PLP_LENGTH"] = plp_length + + # PLP - Variable length (Decode using struct) + plp = atr_bytes[9 + dllp_length : 9 + dllp_length + plp_length] + atr["PLP"] = plp.hex().upper() + if plp_length >= 2: + atr["MCF"] = struct.unpack(">H", plp[:2])[0] + if plp_length >= 3: + atr["CONFIGURATION"] = plp[2] + if plp_length >= 4: + atr["MPOT"] = plp[3] + if plp_length >= 6: + atr["SEGT"], atr["WUT"] = struct.unpack(">HH", plp[4:8]) + + # Length of HB - 1 byte + hb_length = atr_bytes[9 + dllp_length + plp_length] + atr["HB_LENGTH"] = hb_length + # HB - Variable length + hb = atr_bytes[10 + dllp_length + plp_length : 10 + dllp_length + plp_length + hb_length] + atr["HB"] = hb.hex().upper() + return atr + + def _dump_atrs(self, atr): + logging.info(f"PVER (Protocol Version): {atr['PVER']}") + logging.info(f"VID (Vendor ID): {atr['VID']}") + logging.info(f"Length of DLLP: {atr['DLLP_LENGTH']}") + + if "DLLP" in atr: + logging.info(f"DLLP: {atr['DLLP']}") + + if "BWT" in atr and "IFSC" in atr: + logging.info(f"BWT (Block Waiting Time): {atr['BWT']} ms") + logging.info(f"IFSC (Maximum Information Field Size): {atr['IFSC']} bytes") + + logging.info(f"PLID (Physical Layer ID): {atr['PLID']}") + logging.info(f"Length of PLP: {atr['PLP_LENGTH']}") + + if "PLP" in atr: + logging.info(f"PLP: {atr['PLP']}") + + if "MCF" in atr: + logging.info(f"MCF (Max I2C Clock Frequency): {atr['MCF']} kHz") + + if "CONFIGURATION" in atr: + logging.info(f"Configuration: {atr['CONFIGURATION']:#04x}") + + if "MPOT" in atr: + logging.info(f"MPOT (Minimum Polling Time): {atr['MPOT']} ms") + + if "SEGT" in atr and "WUT" in atr: + logging.info(f"SEGT (Secure Element Guard Time): {atr['SEGT']} µs") + logging.info(f"WUT (Wake-Up Time): {atr['WUT']} µs") + + logging.info(f"Length of HB (Historical Bytes): {atr['HB_LENGTH']}") + if "HB" in atr: + logging.info(f"HB (Historical Bytes): {atr['HB']}") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/iso7816.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/iso7816.pyi new file mode 100644 index 000000000..b907567a9 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/iso7816.pyi @@ -0,0 +1,62 @@ +from _typeshed import Incomplete +from micropython import const as const + +_NAD_OFFSET: int +_PCB_OFFSET: int +_LEN_OFFSET: int +_INF_OFFSET: int +_I_BLOCK: int +_I_BLOCK_N: int +_I_BLOCK_M: int +_S_BLOCK: int +_S_BLOCK_REQ: int +_R_BLOCK: int +_R_BLOCK_N: int +_R_BLOCK_ERR: int +_RESYNC_REQ: int +_IFS_REQ: int +_ABORT_REQ: int +_WTX_REQ: int +_END_SESSION_REQ: int +_CHIP_RESET_REQ: int +_GET_ATR_REQ: int +_SOFT_RESET_REQ: int +_CLA_ISO7816: int +_INS_GP_SELECT: int +_STATE_IBLK: int +_STATE_SBLK: int +_STATE_SEND: int +_STATE_RECV: int +_STATE_WAIT: int +_STATE_WWTX: int +_STATE_DONE: int + +def log_enabled(level): ... + +class SmartCard: + seq: int + bus: Incomplete + sad: Incomplete + dad: Incomplete + aid: Incomplete + atr: Incomplete + w_buf: Incomplete + r_buf: Incomplete + s_buf: Incomplete + apdu_buf: Incomplete + block_name: Incomplete + state_name: Incomplete + apdu_status: Incomplete + def __init__(self, bus, nad, aid) -> None: ... + def _block_type(self, pcb): ... + def _block_size(self, buf): ... + def _block_crc16(self, prologue, data, poly: int = 33800, crc: int = 65535): ... + def _block_write(self, buf, delay: int = 0) -> None: ... + def _block_print(self, txrx, *args) -> None: ... + def _block_new(self, buf, btype, **kwargs): ... + def _send_block(self, btype, arg, retry: int = 25, backoff: float = 1.2): ... + def send_apdu(self, cla, ins, p1, p2, data=None, le: int = 0): ... + def reset(self) -> None: ... + def resync(self) -> None: ... + def _parse_atrs(self, atr_bytes): ... + def _dump_atrs(self, atr) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/se05x.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/se05x.py new file mode 100644 index 000000000..0409a5eb1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/se05x.py @@ -0,0 +1,250 @@ +# This file is part of the se05x package. +# Copyright (c) 2024 Arduino SA +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# NXP SE05x EdgeLock device driver. + +import struct +import logging +from time import sleep_ms +from machine import I2C +from machine import Pin +from .iso7816 import SmartCard +from micropython import const + +_RESULT_OK = 1 +_APPLET_NAD = 0x5A +_APPLET_AID = const(b"\xa0\x00\x00\x03\x96\x54\x53\x00\x00\x00\x01\x03\x00\x00\x00\x00") +_CLA_KSE05X = 0x80 + +_INS_WRITE = 0x01 +_INS_READ = 0x02 +_INS_CRYPTO = 0x03 +_INS_MGMT = 0x04 +_INS_PROCESS = 0x05 +_INS_IMPORT_EXTERNAL = 0x06 +_INS_TRANSIENT = 0x80 +_INS_AUTH_OBJECT = 0x40 +_INS_ATTEST = 0x20 + +_P1_DEFAULT = 0x00 +_P1_EC = 0x01 +_P1_AES = 0x03 +_P1_DES = 0x04 +_P1_HMAC = 0x05 +_P1_BINARY = 0x06 +_P1_USERID = 0x07 +_P1_CURVE = 0x0B +_P1_SIGNATURE = 0x0C +_P1_MAC = 0x0D +_P1_CIPHER = 0x0E +_P1_KEY_PRIVATE = 0x40 +_P1_KEY_PUBLIC = 0x20 + +_P2_DEFAULT = 0x00 +_P2_GENERATE = 0x03 +_P2_CREATE = 0x04 +_P2_SIZE = 0x07 +_P2_SIGN = 0x09 +_P2_VERIFY = 0x0A +_P2_SESSION_CREATE = 0x1B +_P2_SESSION_CLOSE = 0x1C +_P2_VERSION = 0x20 +_P2_LIST = 0x25 +_P2_EXIST = 0x27 +_P2_DELETE_OBJECT = 0x28 +_P2_SESSION_USERID = 0x2C +_P2_DH = 0x0F +_P2_ENCRYPT_ONESHOT = 0x37 +_P2_DECRYPT_ONESHOT = 0x38 +_P2_SCP = 0x52 +_P2_ONESHOT = 0x0E + +_TLV_TAG1 = 0x41 +_TLV_TAG2 = 0x42 +_TLV_TAG3 = 0x43 +_TLV_TAG4 = 0x44 +_TLV_TAG5 = 0x45 +_TLV_TAG6 = 0x46 +_TLV_TAG7 = 0x47 +_TLV_TAG8 = 0x48 +_TLV_TAG9 = 0x49 +_TLV_TAG10 = 0x4A +_TLV_TAG11 = 0x4B +_TLV_TAG_SESSION_ID = 0x10 +_TLV_TAG_POLICY = 0x11 +_TLV_TAG_MAX_ATTEMPTS = 0x12 +_TLV_TAG_IMPORT_AUTH_DATA = 0x13 +_TLV_TAG_IMPORT_AUTH_KEY_ID = 0x14 +_TLV_TAG_POLICY_CHECK = 0x15 + +_SIG_ECDSA_SHA_1 = 0x11 +_SIG_ECDSA_SHA_224 = 0x25 +_SIG_ECDSA_SHA_256 = 0x21 +_SIG_ECDSA_SHA_384 = 0x22 +_SIG_ECDSA_SHA_512 = 0x26 + + +class I2CBus: + def __init__(self, addr, freq): + self.addr = addr + self.bus = None + # Scan the first 3 I2C buses + for i in range(3): + try: + bus = I2C(i, freq=freq) + if self.addr in bus.scan(): + logging.info(f"SE05x detected on bus: {i} addr: 0x{addr:02X}") + self.bus = bus + break + except Exception: + pass + if self.bus is None: + raise RuntimeError("Failed to detect SE05x on I2C bus") + + def read(self, buf): + self.bus.readfrom_into(self.addr, buf) + return buf + + def write(self, buf): + self.bus.writeto(self.addr, buf) + + +class SE05X: + def __init__(self, addr=0x48, freq=400_000, rst=Pin("SE05X_EN", Pin.OUT_PP, Pin.PULL_UP)): + self.rst = rst + self.scard = None + self.reset() + self.bus = I2CBus(addr, freq) + self.scard = SmartCard(self.bus, _APPLET_NAD, _APPLET_AID) + self.scard.reset() + self.ecdsa_algo = { + 160: _SIG_ECDSA_SHA_1, + 224: _SIG_ECDSA_SHA_224, + 256: _SIG_ECDSA_SHA_256, + 384: _SIG_ECDSA_SHA_384, + 512: _SIG_ECDSA_SHA_512, + } + self.tlv_offs = 0 + self.tlv_buf = memoryview(bytearray(254)) + + def _tlv_pack(self, fmt, *args): + struct.pack_into(fmt, self.tlv_buf, self.tlv_offs, *args) + self.tlv_offs += struct.calcsize(fmt) + + def _tlv_flush(self): + mv = self.tlv_buf[0 : self.tlv_offs] + self.tlv_offs = 0 + return mv + + def _ecdsa_algo(self, hash_size): + if hash_size * 8 not in self.ecdsa_algo: + raise ValueError("Invalid SHA digest size") + return self.ecdsa_algo[hash_size * 8] + + def reset(self, reset_card=True): + self.rst.low() + sleep_ms(10) + self.rst.high() + sleep_ms(10) + if self.scard is not None: + self.scard.reset() + + def version(self): + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_MGMT, _P1_DEFAULT, _P2_VERSION) + major, minor, patch = struct.unpack(">BBB", resp) + return major, minor, patch + + def read(self, obj_id, size=0): + if not self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} doesn't exist.") + if size == 0: + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_READ, _P1_DEFAULT, _P2_DEFAULT, self._tlv_flush()) + return bytes(resp) + offset = 0 + buf = bytearray() + maxblk = 254 - struct.calcsize("BBIBBHBBH") + while size: + bsize = min(size, maxblk) + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self._tlv_pack(">BBH", _TLV_TAG2, 0x2, offset) + self._tlv_pack(">BBH", _TLV_TAG3, 0x2, bsize) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_READ, _P1_DEFAULT, _P2_DEFAULT, self._tlv_flush()) + buf.extend(resp) + offset += bsize + size -= bsize + return bytes(buf) + + def write(self, obj_id, obj_type, **kwargs): + if self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} already exists.") + + ins = _INS_WRITE | kwargs.get("ins_flags", 0) + if obj_type == _P1_EC: + p1 = _P1_EC + key = kwargs.get("key", (None, None)) + curve_id = kwargs.get("curve", 0x3) + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self._tlv_pack(">BBB", _TLV_TAG2, 0x1, curve_id) + if key[0] is not None: + p1 |= _P1_KEY_PRIVATE + self._tlv_pack(f"BB{len(key[0])}s", _TLV_TAG3, len(key[0]), key[0]) + if key[1] is not None: + p1 |= _P1_KEY_PUBLIC + self._tlv_pack(f"BB{len(key[1])}s", _TLV_TAG4, len(key[1]), key[1]) + if key[0] is None and key[1] is None: + p1 |= _P1_KEY_PRIVATE | _P1_KEY_PUBLIC + self.scard.send_apdu(_CLA_KSE05X, ins, p1, _P2_DEFAULT, self._tlv_flush()) + elif obj_type == _P1_BINARY: + offset = 0 + binary = kwargs["binary"] + maxblk = 254 - struct.calcsize("BBIBBHBBHBBH") + remain = len(binary) + while remain: + bsize = min(remain, maxblk) + data = binary[offset : offset + bsize] + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self._tlv_pack(">BBH", _TLV_TAG2, 0x2, offset) + if offset == 0: + self._tlv_pack(">BBH", _TLV_TAG3, 0x2, remain) + self._tlv_pack(f">BBH{bsize}s", _TLV_TAG4, 0x82, bsize, data) + self.scard.send_apdu(_CLA_KSE05X, ins, _P1_BINARY, _P2_DEFAULT, self._tlv_flush()) + offset += bsize + remain -= bsize + + def delete(self, obj_id): + if not self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} doesn't exist.") + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self.scard.send_apdu(_CLA_KSE05X, _INS_MGMT, _P1_DEFAULT, _P2_DELETE_OBJECT, self._tlv_flush()) + + def exists(self, obj_id): + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_MGMT, _P1_DEFAULT, _P2_EXIST, self._tlv_flush()) + return resp[0] == _RESULT_OK + + def sign(self, obj_id, data): + if not self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} doesn't exist.") + hash_size = len(data) + hash_algo = self._ecdsa_algo(hash_size) + self._tlv_pack(">BBIBBB", _TLV_TAG1, 0x4, obj_id, _TLV_TAG2, 0x1, hash_algo) + self._tlv_pack(f"BB{hash_size}s", _TLV_TAG3, hash_size, data) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_CRYPTO, _P1_SIGNATURE, _P2_SIGN, self._tlv_flush()) + return bytes(resp) + + def verify(self, obj_id, data, sign): + if not self.exists(obj_id): + raise RuntimeError(f"Object with id 0x{obj_id:X} doesn't exist.") + hash_size = len(data) + sign_size = len(sign) + hash_algo = self._ecdsa_algo(hash_size) + self._tlv_pack(">BBI", _TLV_TAG1, 0x4, obj_id) + self._tlv_pack(">BBB", _TLV_TAG2, 0x1, hash_algo) + self._tlv_pack(f"BB{hash_size}s", _TLV_TAG3, hash_size, data) + self._tlv_pack(f"BB{sign_size}s", _TLV_TAG5, sign_size, sign) + resp = self.scard.send_apdu(_CLA_KSE05X, _INS_CRYPTO, _P1_SIGNATURE, _P2_VERIFY, self._tlv_flush()) + return resp[0] == _RESULT_OK diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/se05x.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/se05x.pyi new file mode 100644 index 000000000..db8f302f5 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/se05x/se05x.pyi @@ -0,0 +1,96 @@ +from .iso7816 import SmartCard as SmartCard +from _typeshed import Incomplete + +_RESULT_OK: int +_APPLET_NAD: int +_APPLET_AID: Incomplete +_CLA_KSE05X: int +_INS_WRITE: int +_INS_READ: int +_INS_CRYPTO: int +_INS_MGMT: int +_INS_PROCESS: int +_INS_IMPORT_EXTERNAL: int +_INS_TRANSIENT: int +_INS_AUTH_OBJECT: int +_INS_ATTEST: int +_P1_DEFAULT: int +_P1_EC: int +_P1_AES: int +_P1_DES: int +_P1_HMAC: int +_P1_BINARY: int +_P1_USERID: int +_P1_CURVE: int +_P1_SIGNATURE: int +_P1_MAC: int +_P1_CIPHER: int +_P1_KEY_PRIVATE: int +_P1_KEY_PUBLIC: int +_P2_DEFAULT: int +_P2_GENERATE: int +_P2_CREATE: int +_P2_SIZE: int +_P2_SIGN: int +_P2_VERIFY: int +_P2_SESSION_CREATE: int +_P2_SESSION_CLOSE: int +_P2_VERSION: int +_P2_LIST: int +_P2_EXIST: int +_P2_DELETE_OBJECT: int +_P2_SESSION_USERID: int +_P2_DH: int +_P2_ENCRYPT_ONESHOT: int +_P2_DECRYPT_ONESHOT: int +_P2_SCP: int +_P2_ONESHOT: int +_TLV_TAG1: int +_TLV_TAG2: int +_TLV_TAG3: int +_TLV_TAG4: int +_TLV_TAG5: int +_TLV_TAG6: int +_TLV_TAG7: int +_TLV_TAG8: int +_TLV_TAG9: int +_TLV_TAG10: int +_TLV_TAG11: int +_TLV_TAG_SESSION_ID: int +_TLV_TAG_POLICY: int +_TLV_TAG_MAX_ATTEMPTS: int +_TLV_TAG_IMPORT_AUTH_DATA: int +_TLV_TAG_IMPORT_AUTH_KEY_ID: int +_TLV_TAG_POLICY_CHECK: int +_SIG_ECDSA_SHA_1: int +_SIG_ECDSA_SHA_224: int +_SIG_ECDSA_SHA_256: int +_SIG_ECDSA_SHA_384: int +_SIG_ECDSA_SHA_512: int + +class I2CBus: + addr: Incomplete + bus: Incomplete + def __init__(self, addr, freq) -> None: ... + def read(self, buf): ... + def write(self, buf) -> None: ... + +class SE05X: + rst: Incomplete + scard: Incomplete + bus: Incomplete + ecdsa_algo: Incomplete + tlv_offs: int + tlv_buf: Incomplete + def __init__(self, addr: int = 72, freq: int = 400000, rst=...) -> None: ... + def _tlv_pack(self, fmt, *args) -> None: ... + def _tlv_flush(self): ... + def _ecdsa_algo(self, hash_size): ... + def reset(self, reset_card: bool = True) -> None: ... + def version(self): ... + def read(self, obj_id, size: int = 0): ... + def write(self, obj_id, obj_type, **kwargs) -> None: ... + def delete(self, obj_id) -> None: ... + def exists(self, obj_id): ... + def sign(self, obj_id, data): ... + def verify(self, obj_id, data, sign): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/__init__.py new file mode 100644 index 000000000..908375fdb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/__init__.py @@ -0,0 +1,29 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from .senml_base import SenmlBase +from .senml_pack import SenmlPack +from .senml_record import SenmlRecord +from .senml_unit import SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/__init__.pyi new file mode 100644 index 000000000..c72285dc4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/__init__.pyi @@ -0,0 +1,4 @@ +from .senml_base import SenmlBase as SenmlBase +from .senml_pack import SenmlPack as SenmlPack +from .senml_record import SenmlRecord as SenmlRecord +from .senml_unit import SenmlUnits as SenmlUnits diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_base.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_base.py new file mode 100644 index 000000000..b277c9477 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_base.py @@ -0,0 +1,30 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +class SenmlBase(object): + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_base.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_base.pyi new file mode 100644 index 000000000..240f185ce --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_base.pyi @@ -0,0 +1,4 @@ +class SenmlBase: + """ + the base class for all senml objects. + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_pack.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_pack.py new file mode 100644 index 000000000..5a0554467 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_pack.py @@ -0,0 +1,358 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +from senml.senml_record import SenmlRecord +from senml.senml_base import SenmlBase +import json +import cbor2 + + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + def __init__(self, list): + self._list = list + self._index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self._index < len(self._list): + res = self._list[self._index] + self._index += 1 + return res + else: + raise StopIteration + + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings = { + "bn": "bn", + "bt": "bt", + "bu": "bu", + "bv": "bv", + "bs": "bs", + "n": "n", + "u": "u", + "v": "v", + "vs": "vs", + "vb": "vb", + "vd": "vd", + "s": "s", + "t": "t", + "ut": "ut", + } + + def __init__(self, name, callback=None): + """ + initialize the object + :param name: {string} the name of the pack + """ + self._data = [] + self.name = name + self._base_value = None + self._base_time = None + self._base_sum = None + self.base_unit = None + self._parent = None # a pack can also be the child of another pack. + self.actuate = callback # actuate callback function + + def __iter__(self): + return SenmlPackIterator(self._data) + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + return self._base_value + + @base_value.setter + def base_value(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_value") + self._base_value = value + + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + return self._base_sum + + @base_sum.setter + def base_sum(self, value): + """ + set the base value. + :param value: only number allowed + :return: + """ + self._check_value_type(value, "base_sum") + self._base_sum = value + + @property + def base_time(self): + return self._base_time + + @base_time.setter + def base_time(self, value): + self._check_value_type(value, "base_time") + self._base_time = value + + def _check_value_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + def from_json(self, data): + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + records = json.loads(data) # load the raw senml data + self._process_incomming_data(records, SenmlPack.json_mappings) + + def _process_incomming_data(self, records, naming_map): + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + cur_pack_el = self + new_pack = False + for item in records: + if naming_map["bn"] in item: # ref to a pack element, either this or a child pack. + if item[naming_map["bn"]] != self.name: + pack_el = [x for x in self._data if x.name == item[naming_map["bn"]]] + else: + pack_el = [self] + if len(pack_el) > 0: + cur_pack_el = pack_el[0] + new_pack = False + else: + device = SenmlPack(item[naming_map["bn"]]) + self._data.append(device) + cur_pack_el = device + new_pack = True + + if ( + naming_map["bv"] in item + ): # need to copy the base value assigned to the pack element so we can do proper conversion for actuators. + cur_pack_el.base_value = item[naming_map["bv"]] + + rec_el = [x for x in cur_pack_el._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + else: + rec_el = [x for x in self._data if x.name == item[naming_map["n"]]] + if len(rec_el) > 0: + rec_el[0].do_actuate(item, naming_map) + elif new_pack: + self.do_actuate(item, naming_map, cur_pack_el) + else: + cur_pack_el.do_actuate(item, naming_map) + + def do_actuate(self, raw, naming_map, device=None): + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + rec = SenmlRecord(raw[naming_map["n"]]) + if device: + device.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=device) + else: + self.add(rec) + rec._from_raw(raw, naming_map) + if self.actuate: + self.actuate(rec, device=None) + + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + converted = [] + self._build_rec_dict(SenmlPack.json_mappings, converted) + return json.dumps(converted) + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + internalList = [] + for item in self._data: + item._build_rec_dict(naming_map, internalList) + if len(internalList) > 0: + first_rec = internalList[0] + else: + first_rec = {} + internalList.append(first_rec) + + if self.name: + first_rec[naming_map["bn"]] = self.name + if self.base_value: + first_rec[naming_map["bv"]] = self.base_value + if self.base_unit: + first_rec[naming_map["bu"]] = self.base_unit + if self.base_sum: + first_rec[naming_map["bs"]] = self.base_sum + if self.base_time: + first_rec[naming_map["bt"]] = self.base_time + appendTo.extend(internalList) + + def from_cbor(self, data): + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + records = cbor2.loads(data) # load the raw senml data + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + self._process_incomming_data(records, naming_map) + + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + naming_map = { + "bn": -2, + "bt": -3, + "bu": -4, + "bv": -5, + "bs": -16, + "n": 0, + "u": 1, + "v": 2, + "vs": 3, + "vb": 4, + "vd": 8, + "s": 5, + "t": 6, + "ut": 7, + } + converted = [] + self._build_rec_dict(naming_map, converted) + return cbor2.dumps(converted) + + def add(self, item): + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if item._parent is not None: + raise Exception("item is already part of a pack") + + self._data.append(item) + item._parent = self + + def remove(self, item): + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + if not (isinstance(item, SenmlBase)): + raise Exception("invalid type of param, SenmlRecord or SenmlPack expected") + if not item._parent == self: + raise Exception("item is not part of this pack") + + self._data.remove(item) + item._parent = None + + def clear(self): + """ + clear the list of the pack + :return: None + """ + for item in self._data: + item._parent = None + self._data = [] diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_pack.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_pack.pyi new file mode 100644 index 000000000..57a0cf547 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_pack.pyi @@ -0,0 +1,143 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase +from senml.senml_record import SenmlRecord as SenmlRecord + +class SenmlPackIterator: + """an iterator to walk over all records in a pack""" + + _list: Incomplete + _index: int + def __init__(self, list) -> None: ... + def __iter__(self): ... + def __next__(self): ... + +class SenmlPack(SenmlBase): + """ + represents a sneml pack object. This can contain multiple records but also other (child) pack objects. + When the pack object only contains records, it represents the data of a device. + If the pack object has child pack objects, then it represents a gateway + """ + + json_mappings: Incomplete + _data: Incomplete + name: Incomplete + _base_value: Incomplete + _base_time: Incomplete + _base_sum: Incomplete + base_unit: Incomplete + _parent: Incomplete + actuate: Incomplete + def __init__(self, name, callback=None) -> None: + """ + initialize the object + :param name: {string} the name of the pack + """ + def __iter__(self): ... + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + @property + def base_value(self): + """ + the base value of the pack. + :return: a number + """ + @base_value.setter + def base_value(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_sum(self): + """ + the base sum of the pack. + :return: a number + """ + @base_sum.setter + def base_sum(self, value) -> None: + """ + set the base value. + :param value: only number allowed + :return: + """ + @property + def base_time(self): ... + @base_time.setter + def base_time(self, value) -> None: ... + def _check_value_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def from_json(self, data) -> None: + """ + parse a json string and convert it to a senml pack structure + :param data: a string containing json data. + :return: None, will r + """ + def _process_incomming_data(self, records, naming_map) -> None: + """ + generic processor for incomming data (actuators. + :param records: the list of raw senml data, parsed from a json or cbor structure + :param naming_map: translates cbor to json field names (when needed). + :return: None + """ + def do_actuate(self, raw, naming_map, device=None) -> None: + """ + called while parsing incoming data for a record that is not yet part of this pack object. + adds a new record and raises the actuate callback of the pack with the newly created record as argument + :param naming_map: + :param device: optional: if the device was not found + :param raw: the raw record definition, as found in the json structure. this still has invalid labels. + :return: None + """ + def to_json(self): + """ + render the content of this object to a string. + :return: a string representing the senml pack object + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a senml object with the proper naming in place. + This can be recursive: a pack can contain other packs. + :param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor + :return: + """ + def from_cbor(self, data) -> None: + """ + parse a cbor data byte array to a senml pack structure. + :param data: a byte array. + :return: None + """ + def to_cbor(self): + """ + render the content of this object to a cbor byte array + :return: a byte array + """ + def add(self, item) -> None: + """ + adds the item to the list of records + :param item: {SenmlRecord} the item that needs to be added to the pack + :return: None + """ + def remove(self, item) -> None: + """ + removes the item from the list of records + :param item: {SenmlRecord} the item that needs to be removed + :return: None + """ + def clear(self) -> None: + """ + clear the list of the pack + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_record.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_record.py new file mode 100644 index 000000000..b5b07b0bc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_record.py @@ -0,0 +1,240 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import binascii +from senml.senml_base import SenmlBase + + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + def __init__(self, name, **kwargs): + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + self.__parent = None # using double __ cause it's a field for an internal property + self._unit = None # declare and init internal fields + self._value = None + self._time = None + self._sum = None + self._update_time = None + + self._parent = None # internal reference to the parent object + self.name = name + self.unit = kwargs.get("unit", None) + self.value = kwargs.get("value", None) + self.time = kwargs.get("time", None) + self.sum = kwargs.get("sum", None) + self.update_time = kwargs.get("update_time", None) + self.actuate = kwargs.get("callback", None) # actuate callback function + + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + if self._parent: + self._parent.remove(self) + + def _check_value_type(self, value): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not ( + isinstance(value, bool) + or isinstance(value, int) + or isinstance(value, float) + or isinstance(value, bytearray) + or isinstance(value, str) + ): + raise Exception("invalid type for value, only numbers, strings, boolean and byte arrays allowed") + + def _check_number_type(self, value, field_name): + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + if value is not None: + if not (isinstance(value, int) or isinstance(value, float)): + raise Exception("invalid type for " + field_name + ", only numbers allowed") + + @property + def value(self): + """get the value currently assigned to the object""" + return self._value + + @value.setter + def value(self, value): + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + self._check_value_type(value) + self._value = value + + @property + def time(self): + return self._time + + @time.setter + def time(self, value): + self._check_number_type(value, "time") + self._time = value + + @property + def update_time(self): + return self._update_time + + @update_time.setter + def update_time(self, value): + self._check_number_type(value, "update_time") + self._update_time = value + + @property + def sum(self): + return self._sum + + @sum.setter + def sum(self, value): + self._check_number_type(value, "sum") + self._sum = value + + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + return self.__parent + + @_parent.setter + def _parent(self, value): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + self.__parent = value + + def _build_rec_dict(self, naming_map, appendTo): + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + result = {} + + if self.name: + result[naming_map["n"]] = self.name + + if self._sum: + if self._parent and self._parent.base_sum: + result[naming_map["s"]] = self._sum - self._parent.base_sum + else: + result[naming_map["s"]] = self._sum + elif isinstance(self._value, bool): + result[naming_map["vb"]] = self._value + elif isinstance(self._value, int) or isinstance(self._value, float): + if self._parent and self._parent.base_value: + result[naming_map["v"]] = self._value - self._parent.base_value + else: + result[naming_map["v"]] = self._value + elif isinstance(self._value, str): + result[naming_map["vs"]] = self._value + elif isinstance(self._value, bytearray): + if naming_map["vd"] == "vd": # neeed to make a distinction between json (needs base64) and cbor (needs binary) + result[naming_map["vd"]] = binascii.b2a_base64(self._value, newline=False).decode("utf8") + else: + result[naming_map["vd"]] = self._value + else: + raise Exception("sum or value of type bootl, number, string or byte-array is required") + + if self._time: + if self._parent and self._parent.base_time: + result[naming_map["t"]] = self._time - self._parent.base_time + else: + result[naming_map["t"]] = self._time + + if self.unit: + result[naming_map["u"]] = self.unit + + if self._update_time: + if self._parent and self._parent.base_time: + result[naming_map["ut"]] = self._update_time - self._parent.base_time + else: + result[naming_map["ut"]] = self._update_time + + appendTo.append(result) + + def _from_raw(self, raw, naming_map): + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + if naming_map["v"] in raw: + val = raw[naming_map["v"]] + if self._parent and self._parent.base_value: + val += self._parent.base_value + elif naming_map["vs"] in raw: + val = raw[naming_map["vs"]] + elif naming_map["vb"] in raw: + val = raw[naming_map["vb"]] + elif naming_map["vd"] in raw: + val = binascii.a2b_base64(raw[naming_map["vb"]]) + else: + val = None + self.value = val + + def do_actuate(self, raw, naming_map): + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ + self._from_raw(raw, naming_map) + if self.actuate: + self.actuate(self) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_record.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_record.pyi new file mode 100644 index 000000000..61c0c7c05 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_record.pyi @@ -0,0 +1,104 @@ +import types +from _typeshed import Incomplete +from senml.senml_base import SenmlBase as SenmlBase + +class SenmlRecord(SenmlBase): + """represents a single value in a senml pack object""" + + __parent: Incomplete + _unit: Incomplete + _value: Incomplete + _time: Incomplete + _sum: Incomplete + _update_time: Incomplete + name: Incomplete + unit: Incomplete + actuate: Incomplete + def __init__(self, name, **kwargs) -> None: + """ + create a new senml record + :param kwargs: optional parameters: + - value: the value to store in the record + - time: the timestamp to use (when was the value measured) + - name: the name of hte record + - unit: unit value + - sum: sum value + - update_time: max time before sensor will provide an updated reading + - callback: a callback function taht will be called when actuator data has been found. Expects no params + """ + def __enter__(self): + """ + for supporting the 'with' statement + :return: self + """ + def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: + """ + when destroyed in a 'with' statement, make certain that the item is removed from the parent list. + :return: None + """ + def _check_value_type(self, value) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + def _check_number_type(self, value, field_name) -> None: + """ + checks if the type of value is allowed for senml + :return: None, raisee exception if not ok. + """ + @property + def value(self): + """get the value currently assigned to the object""" + @value.setter + def value(self, value) -> None: + """set the current value. Will not automatically update the time stamp. This has to be done seperatly for more + finegrained control + Note: when the value is a float, you can control rounding in the rendered output by using the function + round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2) + """ + @property + def time(self): ... + @time.setter + def time(self, value) -> None: ... + @property + def update_time(self): ... + @update_time.setter + def update_time(self, value) -> None: ... + @property + def sum(self): ... + @sum.setter + def sum(self, value) -> None: ... + @property + def _parent(self): + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + @_parent.setter + def _parent(self, value) -> None: + """ + the parent pack object for this record. This is a property so that inheriters can override and do custom + actions when the parent is set (like passing it on to their children + :return: + """ + def _build_rec_dict(self, naming_map, appendTo) -> None: + """ + converts the object to a dictionary that can be rendered to senml. + :param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the + form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor) + :return: a senml dictionary representation of the record + """ + def _from_raw(self, raw, naming_map) -> None: + """ + extracts te data from the raw record. Used during parsing of incoming data. + :param raw: a raw senml record which still contains the original field names + :param naming_map: used to map cbor names to json field names + :return: + """ + def do_actuate(self, raw, naming_map) -> None: + """ + called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it. + :param raw: raw senml object + :return: None + """ diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_unit.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_unit.py new file mode 100644 index 000000000..bf7753c4d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_unit.py @@ -0,0 +1,89 @@ +""" +The MIT License (MIT) + +Copyright (c) 2023 Arduino SA +Copyright (c) 2018 KPN (Jan Bogaerts) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +def enum(**enums): + return type("Enum", (), enums) + + +SenmlUnits = enum( + SENML_UNIT_METER="m", + SENML_UNIT_KILOGRAM="kg", + SENML_UNIT_GRAM="g", + SENML_UNIT_SECOND="s", + SENML_UNIT_AMPERE="A", + SENML_UNIT_KELVIN="K", + SENML_UNIT_CANDELA="cd", + SENML_UNIT_MOLE="mol", + SENML_UNIT_HERTZ="Hz", + SENML_UNIT_RADIAN="rad", + SENML_UNIT_STERADIAN="sr", + SENML_UNIT_NEWTON="N", + SENML_UNIT_PASCAL="Pa", + SENML_UNIT_JOULE="J", + SENML_UNIT_WATT="W", + SENML_UNIT_COULOMB="C", + SENML_UNIT_VOLT="V", + SENML_UNIT_FARAD="F", + SENML_UNIT_OHM="Ohm", + SENML_UNIT_SIEMENS="S", + SENML_UNIT_WEBER="Wb", + SENML_UNIT_TESLA="T", + SENML_UNIT_HENRY="H", + SENML_UNIT_DEGREES_CELSIUS="Cel", + SENML_UNIT_LUMEN="lm", + SENML_UNIT_LUX="lx", + SENML_UNIT_BECQUEREL="Bq", + SENML_UNIT_GRAY="Gy", + SENML_UNIT_SIEVERT="Sv", + SENML_UNIT_KATAL="kat", + SENML_UNIT_SQUARE_METER="m2", + SENML_UNIT_CUBIC_METER="m3", + SENML_UNIT_LITER="l", + SENML_UNIT_VELOCITY="m/s", + SENML_UNIT_ACCELERATION="m/s2", + SENML_UNIT_CUBIC_METER_PER_SECOND="m3/s", + SENML_UNIT_LITER_PER_SECOND="l/s", + SENML_UNIT_WATT_PER_SQUARE_METER="W/m2", + SENML_UNIT_CANDELA_PER_SQUARE_METER="cd/m2", + SENML_UNIT_BIT="bit", + SENML_UNIT_BIT_PER_SECOND="bit/s", + SENML_UNIT_DEGREES_LATITUDE="lat", + SENML_UNIT_DEGREES_LONGITUDE="lon", + SENML_UNIT_PH="pH", + SENML_UNIT_DECIBEL="db", + SENML_UNIT_DECIBEL_RELATIVE_TO_1_W="dBW", + SENML_UNIT_BEL="Bspl", + SENML_UNIT_COUNTER="count", + SENML_UNIT_RATIO="//", + SENML_UNIT_RELATIVE_HUMIDITY="%RH", + SENML_UNIT_PERCENTAGE_REMAINING_BATTERY_LEVEL="%EL", + SENML_UNIT_SECONDS_REMAINING_BATTERY_LEVEL="EL", + SENML_UNIT_EVENT_RATE_PER_SECOND="1/s", + SENML_UNIT_EVENT_RATE_PER_MINUTE="1/min", + SENML_UNIT_BPM="beat/min", + SENML_UNIT_BEATS="beats", + SENML_UNIT_SIEMENS_PER_METER="S/m", +) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_unit.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_unit.pyi new file mode 100644 index 000000000..6b3e7ae68 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/senml/senml_unit.pyi @@ -0,0 +1,5 @@ +from _typeshed import Incomplete + +def enum(**enums): ... + +SenmlUnits: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/time.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/time.py new file mode 100644 index 000000000..f79ab8a3b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/time.py @@ -0,0 +1,79 @@ +from utime import * +from micropython import const + +_TS_YEAR = 0 +_TS_MON = 1 +_TS_MDAY = 2 +_TS_HOUR = 3 +_TS_MIN = 4 +_TS_SEC = 5 +_TS_WDAY = 6 +_TS_YDAY = 7 +_TS_ISDST = 8 + +_WDAY = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") +_MDAY = const( + ( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ) +) + + +def strftime(datefmt, ts): + from io import StringIO + + fmtsp = False + ftime = StringIO() + for k in datefmt: + if fmtsp: + if k == "a": + ftime.write(_WDAY[ts[_TS_WDAY]][0:3]) + elif k == "A": + ftime.write(_WDAY[ts[_TS_WDAY]]) + elif k == "b": + ftime.write(_MDAY[ts[_TS_MON] - 1][0:3]) + elif k == "B": + ftime.write(_MDAY[ts[_TS_MON] - 1]) + elif k == "d": + ftime.write("%02d" % ts[_TS_MDAY]) + elif k == "H": + ftime.write("%02d" % ts[_TS_HOUR]) + elif k == "I": + ftime.write("%02d" % (ts[_TS_HOUR] % 12)) + elif k == "j": + ftime.write("%03d" % ts[_TS_YDAY]) + elif k == "m": + ftime.write("%02d" % ts[_TS_MON]) + elif k == "M": + ftime.write("%02d" % ts[_TS_MIN]) + elif k == "P": + ftime.write("AM" if ts[_TS_HOUR] < 12 else "PM") + elif k == "S": + ftime.write("%02d" % ts[_TS_SEC]) + elif k == "w": + ftime.write(str(ts[_TS_WDAY])) + elif k == "y": + ftime.write("%02d" % (ts[_TS_YEAR] % 100)) + elif k == "Y": + ftime.write(str(ts[_TS_YEAR])) + else: + ftime.write(k) + fmtsp = False + elif k == "%": + fmtsp = True + else: + ftime.write(k) + val = ftime.getvalue() + ftime.close() + return val diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/time.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/time.pyi new file mode 100644 index 000000000..26b0e4b08 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/time.pyi @@ -0,0 +1,59 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. +""" + +from __future__ import annotations +from utime import * +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TS_YEAR: int +_TS_MON: int +_TS_MDAY: int +_TS_HOUR: int +_TS_MIN: int +_TS_SEC: int +_TS_WDAY: int +_TS_YDAY: int +_TS_ISDST: int +_WDAY: Incomplete +_MDAY: Incomplete +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def strftime(datefmt, ts): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/ARDUINO_PORTENTA_H7/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/modules.json new file mode 100644 index 000000000..fbfd51b97 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/modules.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "GARATRONIC_PYBSTICK26_F411", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "ssd1306.py", + "module": "ssd1306" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/ssd1306.py b/stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/ssd1306.py new file mode 100644 index 000000000..ec511555e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/ssd1306.py @@ -0,0 +1,164 @@ +# MicroPython SSD1306 OLED driver, I2C and SPI interfaces + +from micropython import const +import framebuf + + +# register definitions +SET_CONTRAST = 0x81 +SET_ENTIRE_ON = 0xA4 +SET_NORM_INV = 0xA6 +SET_DISP = 0xAE +SET_MEM_ADDR = 0x20 +SET_COL_ADDR = 0x21 +SET_PAGE_ADDR = 0x22 +SET_DISP_START_LINE = 0x40 +SET_SEG_REMAP = 0xA0 +SET_MUX_RATIO = 0xA8 +SET_IREF_SELECT = 0xAD +SET_COM_OUT_DIR = 0xC0 +SET_DISP_OFFSET = 0xD3 +SET_COM_PIN_CFG = 0xDA +SET_DISP_CLK_DIV = 0xD5 +SET_PRECHARGE = 0xD9 +SET_VCOM_DESEL = 0xDB +SET_CHARGE_PUMP = 0x8D + + +# Subclassing FrameBuffer provides support for graphics primitives +# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html +class SSD1306(framebuf.FrameBuffer): + def __init__(self, width, height, external_vcc): + self.width = width + self.height = height + self.external_vcc = external_vcc + self.pages = self.height // 8 + self.buffer = bytearray(self.pages * self.width) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + self.init_display() + + def init_display(self): + for cmd in ( + SET_DISP, # display off + # address setting + SET_MEM_ADDR, + 0x00, # horizontal + # resolution and layout + SET_DISP_START_LINE, # start at line 0 + SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 + SET_MUX_RATIO, + self.height - 1, + SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 + SET_DISP_OFFSET, + 0x00, + SET_COM_PIN_CFG, + 0x02 if self.width > 2 * self.height else 0x12, + # timing and driving scheme + SET_DISP_CLK_DIV, + 0x80, + SET_PRECHARGE, + 0x22 if self.external_vcc else 0xF1, + SET_VCOM_DESEL, + 0x30, # 0.83*Vcc + # display + SET_CONTRAST, + 0xFF, # maximum + SET_ENTIRE_ON, # output follows RAM contents + SET_NORM_INV, # not inverted + SET_IREF_SELECT, + 0x30, # enable internal IREF during display on + # charge pump + SET_CHARGE_PUMP, + 0x10 if self.external_vcc else 0x14, + SET_DISP | 0x01, # display on + ): # on + self.write_cmd(cmd) + self.fill(0) + self.show() + + def poweroff(self): + self.write_cmd(SET_DISP) + + def poweron(self): + self.write_cmd(SET_DISP | 0x01) + + def contrast(self, contrast): + self.write_cmd(SET_CONTRAST) + self.write_cmd(contrast) + + def invert(self, invert): + self.write_cmd(SET_NORM_INV | (invert & 1)) + + def rotate(self, rotate): + self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3)) + self.write_cmd(SET_SEG_REMAP | (rotate & 1)) + + def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width != 128: + # narrow displays use centred columns + col_offset = (128 - self.width) // 2 + x0 += col_offset + x1 += col_offset + self.write_cmd(SET_COL_ADDR) + self.write_cmd(x0) + self.write_cmd(x1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + self.write_data(self.buffer) + + +class SSD1306_I2C(SSD1306): + def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): + self.i2c = i2c + self.addr = addr + self.temp = bytearray(2) + self.write_list = [b"\x40", None] # Co=0, D/C#=1 + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.temp[0] = 0x80 # Co=1, D/C#=0 + self.temp[1] = cmd + self.i2c.writeto(self.addr, self.temp) + + def write_data(self, buf): + self.write_list[1] = buf + self.i2c.writevto(self.addr, self.write_list) + + +class SSD1306_SPI(SSD1306): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): + self.rate = 10 * 1024 * 1024 + dc.init(dc.OUT, value=0) + res.init(res.OUT, value=0) + cs.init(cs.OUT, value=1) + self.spi = spi + self.dc = dc + self.res = res + self.cs = cs + import time + + self.res(1) + time.sleep_ms(1) + self.res(0) + time.sleep_ms(10) + self.res(1) + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(0) + self.cs(0) + self.spi.write(bytearray([cmd])) + self.cs(1) + + def write_data(self, buf): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(1) + self.cs(0) + self.spi.write(buf) + self.cs(1) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/ssd1306.pyi b/stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/ssd1306.pyi new file mode 100644 index 000000000..ca4f897fd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/GARATRONIC_PYBSTICK26_F411/ssd1306.pyi @@ -0,0 +1,56 @@ +import framebuf +from _typeshed import Incomplete +from micropython import const as const + +SET_CONTRAST: int +SET_ENTIRE_ON: int +SET_NORM_INV: int +SET_DISP: int +SET_MEM_ADDR: int +SET_COL_ADDR: int +SET_PAGE_ADDR: int +SET_DISP_START_LINE: int +SET_SEG_REMAP: int +SET_MUX_RATIO: int +SET_IREF_SELECT: int +SET_COM_OUT_DIR: int +SET_DISP_OFFSET: int +SET_COM_PIN_CFG: int +SET_DISP_CLK_DIV: int +SET_PRECHARGE: int +SET_VCOM_DESEL: int +SET_CHARGE_PUMP: int + +class SSD1306(framebuf.FrameBuffer): + width: Incomplete + height: Incomplete + external_vcc: Incomplete + pages: Incomplete + buffer: Incomplete + def __init__(self, width, height, external_vcc) -> None: ... + def init_display(self) -> None: ... + def poweroff(self) -> None: ... + def poweron(self) -> None: ... + def contrast(self, contrast) -> None: ... + def invert(self, invert) -> None: ... + def rotate(self, rotate) -> None: ... + def show(self) -> None: ... + +class SSD1306_I2C(SSD1306): + i2c: Incomplete + addr: Incomplete + temp: Incomplete + write_list: Incomplete + def __init__(self, width, height, i2c, addr: int = 60, external_vcc: bool = False) -> None: ... + def write_cmd(self, cmd) -> None: ... + def write_data(self, buf) -> None: ... + +class SSD1306_SPI(SSD1306): + rate: Incomplete + spi: Incomplete + dc: Incomplete + res: Incomplete + cs: Incomplete + def __init__(self, width, height, spi, dc, res, cs, external_vcc: bool = False) -> None: ... + def write_cmd(self, cmd) -> None: ... + def write_data(self, buf) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/modules.json new file mode 100644 index 000000000..9629b6790 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/modules.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "GENERIC", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/appupdate.py b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/appupdate.py new file mode 100644 index 000000000..071fa6bd4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/appupdate.py @@ -0,0 +1,65 @@ +# Application firmware update function for LEGO_HUB_NO6. +# MIT license; Copyright (c) 2022-2024 Damien P. George + +from micropython import const +import random +import machine +import fwupdate +import spiflash +import pyb + +_IOCTL_BLOCK_COUNT = 4 +_IOCTL_BLOCK_SIZE = 5 + +# Mboot addresses the external SPI flash at this location. +_MBOOT_SPIFLASH_BASE_ADDR = 0x80000000 + +# The raw filesystem is in the first 1MiB of external SPI flash, +# but skip the first and last flash sectors. +_RAW_FILESYSTEM_ADDR = 4 * 1024 +_RAW_FILESYSTEM_LEN = 1016 * 1024 + + +def _copy_file_to_raw_filesystem(filename, flash, block): + block_count = flash.ioctl(_IOCTL_BLOCK_COUNT, 0) + block_size = flash.ioctl(_IOCTL_BLOCK_SIZE, 0) + buf = bytearray(block_size) + with open(filename, "rb") as file: + while True: + n = file.readinto(buf) + if not n: + break + flash.writeblocks(block, buf) + block += 1 + if block >= block_count: + print("|", end="") + block = 0 + print(".", end="") + print() + + +def update_app(filename): + print(f"Updating application firmware from {filename}") + + # We can't use pyb.Flash() because we need to write to the "reserved" 1M area. + flash = spiflash.SPIFlash(start=_RAW_FILESYSTEM_ADDR, len=_RAW_FILESYSTEM_LEN) + + # Partition the raw filesystem into two segments for wear levelling. + block_count = flash.ioctl(_IOCTL_BLOCK_COUNT, 0) + block_size = flash.ioctl(_IOCTL_BLOCK_SIZE, 0) + block_start = random.randrange(0, block_count) + print(f"Raw filesystem block layout: 0 .. {block_start} .. {block_count}") + + # Copy the file to the special raw filesystem. + _copy_file_to_raw_filesystem(filename, flash, block_start) + + # Enter mboot with a request to do a filesystem-load update. + # Note: the filename doesn't mean anything here, but still needs to be non-empty. + fwupdate.update_mpy( + filename, + fs_type=fwupdate.VFS_RAW, + fs_base=_MBOOT_SPIFLASH_BASE_ADDR + _RAW_FILESYSTEM_ADDR + block_start * block_size, + fs_len=(block_count - block_start) * block_size, + fs_base2=_MBOOT_SPIFLASH_BASE_ADDR + _RAW_FILESYSTEM_ADDR, + fs_len2=block_start * block_size, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/appupdate.pyi b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/appupdate.pyi new file mode 100644 index 000000000..8c333e148 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/appupdate.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from micropython import const as const + +_IOCTL_BLOCK_COUNT: int +_IOCTL_BLOCK_SIZE: int +_MBOOT_SPIFLASH_BASE_ADDR: int +_RAW_FILESYSTEM_ADDR: Incomplete +_RAW_FILESYSTEM_LEN: Incomplete + +def _copy_file_to_raw_filesystem(filename, flash, block) -> None: ... +def update_app(filename) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/fwupdate.py b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/fwupdate.py new file mode 100644 index 000000000..e9447a2f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/fwupdate.py @@ -0,0 +1,303 @@ +# Update Mboot or MicroPython from a .dfu.gz file on the board's filesystem +# MIT license; Copyright (c) 2019-2022 Damien P. George + +from micropython import const +import struct, time +import deflate, machine, stm + +# Constants to be used with update_mpy +VFS_FAT = 1 +VFS_LFS1 = 2 +VFS_LFS2 = 3 +VFS_RAW = 4 + +# Constants for creating mboot elements. +_ELEM_TYPE_END = 1 +_ELEM_TYPE_MOUNT = 2 +_ELEM_TYPE_FSLOAD = 3 +_ELEM_TYPE_STATUS = 4 + + +def check_mem_contains(addr, buf): + mem8 = stm.mem8 + r = range(len(buf)) + for off in r: + if mem8[addr + off] != buf[off]: + return False + return True + + +def dfu_read(filename): + from binascii import crc32 + + f = open(filename, "rb") + + hdr = f.read(3) + f.seek(0) + if hdr == b"Dfu": + pass + elif hdr == b"\x1f\x8b\x08": + f = deflate.DeflateIO(f, deflate.GZIP) + else: + print("Invalid firmware", filename) + return None + + crc = 0 + elems = [] + + hdr = f.read(11) + crc = crc32(hdr, crc) + sig, ver, size, num_targ = struct.unpack("<5sBIB", hdr) + + file_offset = 11 + + for i in range(num_targ): + hdr = f.read(274) + crc = crc32(hdr, crc) + sig, alt, has_name, name, t_size, num_elem = struct.unpack("<6sBi255sII", hdr) + + file_offset += 274 + file_offset_t = file_offset + for j in range(num_elem): + hdr = f.read(8) + crc = crc32(hdr, crc) + addr, e_size = struct.unpack(" flash.sector0_size: + flash.erase_sector(1) + flash.write(mboot_addr, mboot_fw) + flash.lock() + machine.enable_irq(irq) + + print("New Mboot programmed.") + + if check_mem_contains(mboot_addr, mboot_fw): + print("Verification of new Mboot succeeded.") + else: + print("Verification of new Mboot FAILED! Try rerunning.") + + print("Programming finished, can now reset or turn off.") + + +def _create_element(kind, body): + return bytes([kind, len(body)]) + body + + +def update_app_elements( + filename, + fs_base, + fs_len, + fs_type=VFS_FAT, + fs_blocksize=0, + status_addr=None, + addr_64bit=False, + *, + fs_base2=0, + fs_len2=0, +): + if fs_type != VFS_RAW: + # Check firmware is of .dfu or .dfu.gz type + try: + with open(filename, "rb") as f: + hdr = deflate.DeflateIO(f, deflate.GZIP).read(6) + except Exception: + with open(filename, "rb") as f: + hdr = f.read(6) + if hdr != b"DfuSe\x01": + print("Firmware must be a .dfu(.gz) file.") + return () + + if fs_type in (VFS_LFS1, VFS_LFS2) and not fs_blocksize: + raise Exception("littlefs requires fs_blocksize parameter") + + mount_point = 1 + if fs_type == VFS_RAW: + mount_encoding = " None: ... + def wait_not_busy(self) -> None: ... + def unlock(self) -> None: ... + def lock(self) -> None: ... + def erase_sector(self, sector) -> None: ... + def write(self, addr, buf) -> None: ... + +def update_mboot(filename) -> None: ... +def _create_element(kind, body): ... +def update_app_elements( + filename, + fs_base, + fs_len, + fs_type=..., + fs_blocksize: int = 0, + status_addr=None, + addr_64bit: bool = False, + *, + fs_base2: int = 0, + fs_len2: int = 0, +): ... +def update_mpy(*args, **kwargs) -> None: ... +def get_mboot_version( + mboot_base: int = 134217728, mboot_len: int = 32768, mboot_ver_len: int = 64, valid_prefix: str = "mboot-", include_opts: bool = True +): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/modules.json new file mode 100644 index 000000000..f572b2791 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/modules.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "LEGO_HUB_NO6", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "appupdate.py", + "module": "appupdate" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "fwupdate.py", + "module": "fwupdate" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO6/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/appupdate.py b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/appupdate.py new file mode 100644 index 000000000..071fa6bd4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/appupdate.py @@ -0,0 +1,65 @@ +# Application firmware update function for LEGO_HUB_NO6. +# MIT license; Copyright (c) 2022-2024 Damien P. George + +from micropython import const +import random +import machine +import fwupdate +import spiflash +import pyb + +_IOCTL_BLOCK_COUNT = 4 +_IOCTL_BLOCK_SIZE = 5 + +# Mboot addresses the external SPI flash at this location. +_MBOOT_SPIFLASH_BASE_ADDR = 0x80000000 + +# The raw filesystem is in the first 1MiB of external SPI flash, +# but skip the first and last flash sectors. +_RAW_FILESYSTEM_ADDR = 4 * 1024 +_RAW_FILESYSTEM_LEN = 1016 * 1024 + + +def _copy_file_to_raw_filesystem(filename, flash, block): + block_count = flash.ioctl(_IOCTL_BLOCK_COUNT, 0) + block_size = flash.ioctl(_IOCTL_BLOCK_SIZE, 0) + buf = bytearray(block_size) + with open(filename, "rb") as file: + while True: + n = file.readinto(buf) + if not n: + break + flash.writeblocks(block, buf) + block += 1 + if block >= block_count: + print("|", end="") + block = 0 + print(".", end="") + print() + + +def update_app(filename): + print(f"Updating application firmware from {filename}") + + # We can't use pyb.Flash() because we need to write to the "reserved" 1M area. + flash = spiflash.SPIFlash(start=_RAW_FILESYSTEM_ADDR, len=_RAW_FILESYSTEM_LEN) + + # Partition the raw filesystem into two segments for wear levelling. + block_count = flash.ioctl(_IOCTL_BLOCK_COUNT, 0) + block_size = flash.ioctl(_IOCTL_BLOCK_SIZE, 0) + block_start = random.randrange(0, block_count) + print(f"Raw filesystem block layout: 0 .. {block_start} .. {block_count}") + + # Copy the file to the special raw filesystem. + _copy_file_to_raw_filesystem(filename, flash, block_start) + + # Enter mboot with a request to do a filesystem-load update. + # Note: the filename doesn't mean anything here, but still needs to be non-empty. + fwupdate.update_mpy( + filename, + fs_type=fwupdate.VFS_RAW, + fs_base=_MBOOT_SPIFLASH_BASE_ADDR + _RAW_FILESYSTEM_ADDR + block_start * block_size, + fs_len=(block_count - block_start) * block_size, + fs_base2=_MBOOT_SPIFLASH_BASE_ADDR + _RAW_FILESYSTEM_ADDR, + fs_len2=block_start * block_size, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/appupdate.pyi b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/appupdate.pyi new file mode 100644 index 000000000..8c333e148 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/appupdate.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from micropython import const as const + +_IOCTL_BLOCK_COUNT: int +_IOCTL_BLOCK_SIZE: int +_MBOOT_SPIFLASH_BASE_ADDR: int +_RAW_FILESYSTEM_ADDR: Incomplete +_RAW_FILESYSTEM_LEN: Incomplete + +def _copy_file_to_raw_filesystem(filename, flash, block) -> None: ... +def update_app(filename) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/fwupdate.py b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/fwupdate.py new file mode 100644 index 000000000..e9447a2f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/fwupdate.py @@ -0,0 +1,303 @@ +# Update Mboot or MicroPython from a .dfu.gz file on the board's filesystem +# MIT license; Copyright (c) 2019-2022 Damien P. George + +from micropython import const +import struct, time +import deflate, machine, stm + +# Constants to be used with update_mpy +VFS_FAT = 1 +VFS_LFS1 = 2 +VFS_LFS2 = 3 +VFS_RAW = 4 + +# Constants for creating mboot elements. +_ELEM_TYPE_END = 1 +_ELEM_TYPE_MOUNT = 2 +_ELEM_TYPE_FSLOAD = 3 +_ELEM_TYPE_STATUS = 4 + + +def check_mem_contains(addr, buf): + mem8 = stm.mem8 + r = range(len(buf)) + for off in r: + if mem8[addr + off] != buf[off]: + return False + return True + + +def dfu_read(filename): + from binascii import crc32 + + f = open(filename, "rb") + + hdr = f.read(3) + f.seek(0) + if hdr == b"Dfu": + pass + elif hdr == b"\x1f\x8b\x08": + f = deflate.DeflateIO(f, deflate.GZIP) + else: + print("Invalid firmware", filename) + return None + + crc = 0 + elems = [] + + hdr = f.read(11) + crc = crc32(hdr, crc) + sig, ver, size, num_targ = struct.unpack("<5sBIB", hdr) + + file_offset = 11 + + for i in range(num_targ): + hdr = f.read(274) + crc = crc32(hdr, crc) + sig, alt, has_name, name, t_size, num_elem = struct.unpack("<6sBi255sII", hdr) + + file_offset += 274 + file_offset_t = file_offset + for j in range(num_elem): + hdr = f.read(8) + crc = crc32(hdr, crc) + addr, e_size = struct.unpack(" flash.sector0_size: + flash.erase_sector(1) + flash.write(mboot_addr, mboot_fw) + flash.lock() + machine.enable_irq(irq) + + print("New Mboot programmed.") + + if check_mem_contains(mboot_addr, mboot_fw): + print("Verification of new Mboot succeeded.") + else: + print("Verification of new Mboot FAILED! Try rerunning.") + + print("Programming finished, can now reset or turn off.") + + +def _create_element(kind, body): + return bytes([kind, len(body)]) + body + + +def update_app_elements( + filename, + fs_base, + fs_len, + fs_type=VFS_FAT, + fs_blocksize=0, + status_addr=None, + addr_64bit=False, + *, + fs_base2=0, + fs_len2=0, +): + if fs_type != VFS_RAW: + # Check firmware is of .dfu or .dfu.gz type + try: + with open(filename, "rb") as f: + hdr = deflate.DeflateIO(f, deflate.GZIP).read(6) + except Exception: + with open(filename, "rb") as f: + hdr = f.read(6) + if hdr != b"DfuSe\x01": + print("Firmware must be a .dfu(.gz) file.") + return () + + if fs_type in (VFS_LFS1, VFS_LFS2) and not fs_blocksize: + raise Exception("littlefs requires fs_blocksize parameter") + + mount_point = 1 + if fs_type == VFS_RAW: + mount_encoding = " None: ... + def wait_not_busy(self) -> None: ... + def unlock(self) -> None: ... + def lock(self) -> None: ... + def erase_sector(self, sector) -> None: ... + def write(self, addr, buf) -> None: ... + +def update_mboot(filename) -> None: ... +def _create_element(kind, body): ... +def update_app_elements( + filename, + fs_base, + fs_len, + fs_type=..., + fs_blocksize: int = 0, + status_addr=None, + addr_64bit: bool = False, + *, + fs_base2: int = 0, + fs_len2: int = 0, +): ... +def update_mpy(*args, **kwargs) -> None: ... +def get_mboot_version( + mboot_base: int = 134217728, mboot_len: int = 32768, mboot_ver_len: int = 64, valid_prefix: str = "mboot-", include_opts: bool = True +): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/modules.json new file mode 100644 index 000000000..fc27112a7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/modules.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "LEGO_HUB_NO7", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "appupdate.py", + "module": "appupdate" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "fwupdate.py", + "module": "fwupdate" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/LEGO_HUB_NO7/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/modules.json new file mode 100644 index 000000000..6834daf8b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "NUCLEO_F429ZI", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F429ZI/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/modules.json new file mode 100644 index 000000000..b5e06738f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "NUCLEO_F439ZI", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F439ZI/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/modules.json new file mode 100644 index 000000000..6f827b0c4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "NUCLEO_F746ZG", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F746ZG/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/modules.json new file mode 100644 index 000000000..58a26ca16 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "NUCLEO_F756ZG", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F756ZG/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/modules.json new file mode 100644 index 000000000..9050b550f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "NUCLEO_F767ZI", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_F767ZI/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/modules.json new file mode 100644 index 000000000..b6332d19f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "NUCLEO_H723ZG", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H723ZG/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/modules.json new file mode 100644 index 000000000..84ff11759 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "NUCLEO_H743ZI", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_H743ZI/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/__init__.py new file mode 100644 index 000000000..7f8930b8c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/__init__.py @@ -0,0 +1,40 @@ +# MicroPython lora module +# MIT license; Copyright (c) 2023 Angus Gratton + +from .modem import RxPacket # noqa: F401 + +ok = False # Flag if at least one modem driver package is installed + +# Various lora "sub-packages" + +try: + from .sx126x import * # noqa: F401 + + ok = True +except ImportError as e: + if "no module named 'lora." not in str(e): + raise + +try: + from .sx127x import * # noqa: F401 + + ok = True +except ImportError as e: + if "no module named 'lora." not in str(e): + raise + +try: + from .stm32wl5 import * # noqa: F401 + + ok = True +except ImportError as e: + if "no module named 'lora." not in str(e): + raise + + +if not ok: + raise ImportError( + "Incomplete lora installation. Need at least one of lora-sync, lora-async and one of lora-sx126x, lora-sx127x" + ) + +del ok diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/__init__.pyi new file mode 100644 index 000000000..27a199fc9 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/__init__.pyi @@ -0,0 +1,6 @@ +from .sx126x import * +from .sx127x import * +from .stm32wl5 import * +from .modem import RxPacket as RxPacket + +ok: bool diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/modem.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/modem.py new file mode 100644 index 000000000..2fc8ce521 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/modem.py @@ -0,0 +1,463 @@ +# MicroPython LoRa modem driver base class +# MIT license; Copyright (c) 2023 Angus Gratton +# +# LoRa is a registered trademark or service mark of Semtech Corporation or its affiliates. +import time +from micropython import const, schedule + +# Set to True to get some additional printed debug output. +_DEBUG = False + + +def _clamp(v, vmin, vmax): + # Small utility function to clamp a value 'v' between 'vmin' and 'vmax', inclusive. + return min(max(vmin, v), vmax) + + +def _flag(value, condition): + # Small utility function for returning a bit 'value' or not, based on a + # boolean condition. Can help make expressions to build register values more + # readable. + # + # Note that for value==1, can also rely on int(bool(x)) with one or both + # conversions being implicit, as int(True)==1 and int(False)==0 + # + # There is also (condition and value) but this is (IMO) confusing to read. + return value if condition else 0 + + +class ConfigError(ValueError): + # Raise if there is an error in lora_cfg, saves some duplicated strings + def __init__(self, field): + super().__init__("Invalid lora_cfg {}".format(field)) + + +class BaseModem: + def __init__(self, ant_sw): + self._ant_sw = ant_sw + self._irq_callback = None + + # Common configuration settings that need to be tracked by all modem drivers. + # + # Where modem hardware sets different values after reset, the driver should + # set them back to these defaults (if not provided by the user), so that + # behaviour remains consistent between different modems using the same driver. + self._rf_freq_hz = 0 # Needs to be set via configure() + self._sf = 7 # Spreading factor + self._bw_hz = 125000 # Reset value + self._coding_rate = 5 + self._crc_en = True # use packet CRCs + self._implicit_header = False # implict vs explicit header mode + self._preamble_len = 12 + self._coding_rate = 5 + + # CRC error counter + self.crc_errors = 0 + self.rx_crc_error = False + + # Current state of the modem + + # _rx holds radio recv state: + # + # - False if the radio is not receiving + # - True if the radio is continuously receiving, or performing a single receive with + # no timeout. + # - An int if there is a timeout set, in which case it is the is the receive deadline + # (as a time.ticks_ms() timestamp). + # + # Note that self._rx can be not-False even when the radio hardware is not actually + # receiving, if self._tx is True (send always pauses recv.) + self._rx = False + + # _rx_continuous is True if the modem is in continuous receive mode + # (this value is only valid when self._rx is also True). + self._rx_continuous = False + + # This argument is stored from the parameter of the same name, as set in + # the last call to start_recv() + self._rx_length = None + + # _tx holds radio send state and is simpler, True means sending and + # False means not sending. + self._tx = False + + # timestamp (as time.ticks_ms() result) of last IRQ event + self._last_irq = None + + # values are: + # - lora_cfg["invert_iq_rx"] + # - lora_cfg["invert_iq_tx"] + # - Current modem Invert setting + self._invert_iq = [False, False, False] + + # This hook exists to allow the SyncModem & AsyncModem "mixin-like" + # classes to have some of their own state, without needing to manage the + # fuss of multiple constructor paths. + try: + self._after_init() + except AttributeError: + # If this exception happens here then one of the modem classes without a SyncModem or AsyncModem "mixin-like" class + # has been instantiated. + raise NotImplementedError("Don't instantiate this class directly, instantiate a class from the 'lora' package") + + def standby(self): + # Put the modem into standby. Can be used to cancel a continuous recv, + # or cancel a send before it completes. + # + # Calls the private function which actually sets the mode to standby, and then + # clears all the driver's state flags. + # + # Note this is also called before going to sleep(), to save on duplicated code. + self._standby() + self._rx = False + self._tx = False + self._last_irq = None + if self._ant_sw: + self._ant_sw.idle() + self._radio_isr(None) # "soft ISR" + + def _get_t_sym_us(self): + # Return length of a symbol in microseconds + return 1000_000 * (1 << self._sf) // self._bw_hz + + def _get_ldr_en(self): + # Return true if Low Data Rate should be enabled + # + # The calculation in get_n_symbols_x4() relies on this being the same logic applied + # in the modem configuration routines. + return self._get_t_sym_us() >= 16000 + + def _get_pa_ramp_val(self, lora_cfg, supported): + # Return the PA ramp register index from the list of supported PA ramp + # values. If the requested ramp time is supported by the modem, round up + # to the next supported value. + # + # 'supported' is the list of supported ramp times, must be sorted + # already. + us = int(lora_cfg["pa_ramp_us"]) + + # Find the index of the lowest supported ramp time that is longer or the + # same value as 'us' + for i, v in enumerate(supported): + if v >= us: + return i + # The request ramp time is longer than all this modem's supported ramp times + raise ConfigError("pa_ramp_us") + + def _symbol_offsets(self): + # Called from get_time_on_air_us(). + # + # This function provides a way to implement the different SF5 and SF6 in SX126x, + # by returning two offsets: one for the overall number of symbols, and one for the + # number of bits used to calculate the symbol length of the payload. + return (0, 0) + + def get_n_symbols_x4(self, payload_len): + # Get the number of symbols in a packet (Time-on-Air) for the current + # configured modem settings and the provided payload length in bytes. + # + # Result is in units of "symbols times 4" as there is a fractional term + # in the equation, and we want to limit ourselves to integer arithmetic. + # + # References are: + # - SX1261/2 DS 6.1.4 "LoRa Time-on-Air" + # - SX1276 DS 4.1.1 "Time on air" + # + # Note the two datasheets give the same information in different + # ways. SX1261/62 DS is (IMO) clearer, so this function is based on that + # formula. The result is equivalent to the datasheet value "Nsymbol", + # times 4. + # + # Note also there are unit tests for this function in tests/test_time_on_air.py, + # and that it's been optimised a bit for code size (with impact on readability) + + # Account for a minor difference between SX126x and SX127x: they have + # incompatible SF 5 & 6 modes. + # + # In SX126x when using SF5 or SF6, we apply an offset of +2 symbols to + # the overall preamble symbol count (s_o), and an offset of -8 to the + # payload bit length (b_o). + s_o, b_o = self._symbol_offsets() + + # calculate the bit length of the payload + # + # This is the part inside the max(...,0) in the datasheet + bits = ( + # payload_bytes + 8 * payload_len + # N_bit_crc + + (16 if self._crc_en else 0) + # (4 * SF) + - (4 * self._sf) + # +8 for most modes, except SF5/6 on SX126x where b_o == -8 so these two cancel out + + 8 + + b_o + # N_symbol_header + + (0 if self._implicit_header else 20) + ) + bits = max(bits, 0) + + # "Bits per symbol" denominator is either (4 * SF) or (4 * (SF -2)) + # depending on Low Data Rate Optimization + bps = (self._sf - (2 * self._get_ldr_en())) * 4 + + return ( + # Fixed preamble portion (4.25), times 4 + 17 + # Remainder of equation is an integer number of symbols, times 4 + + 4 + * ( + # configured preamble length + self._preamble_len + + + # optional extra preamble symbols (4.25+2=6.25 for SX1262 SF5,SF6) + s_o + + + # 8 symbol constant overhead + 8 + + + # Payload symbol length + # (this is the term "ceil(bits / 4 * SF) * (CR + 4)" in the datasheet + ((bits + bps - 1) // bps) * self._coding_rate + ) + ) + + def get_time_on_air_us(self, payload_len): + # Return the "Time on Air" in microseconds for a particular + # payload length and the current configured modem settings. + return self._get_t_sym_us() * self.get_n_symbols_x4(payload_len) // 4 + + # Modem ISR routines + # + # ISR implementation is relatively simple, just exists to signal an optional + # callback, record a timestamp, and wake up the hardware if + # needed. Application code is expected to call poll_send() or + # poll_recv() as applicable in order to confirm the modem state. + # + # This is a MP hard irq in some configurations. + def _radio_isr(self, _): + self._last_irq = time.ticks_ms() + if self._irq_callback: + self._irq_callback() + if _DEBUG: + print("_radio_isr") + + def irq_triggered(self): + # Returns True if the ISR has executed since the last time a send or a receive + # started + return self._last_irq is not None + + def set_irq_callback(self, callback): + # Set a function to be called from the radio ISR + # + # This is used by the AsyncModem implementation, but can be called in + # other circumstances to implement custom ISR logic. + # + # Note that callback may be called in hard ISR context. + self._irq_callback = callback + + def _get_last_irq(self): + # Return the _last_irq timestamp if set by an ISR, or the + # current time.time_ms() timestamp otherwise. + if self._last_irq is None: + return time.ticks_ms() + return self._last_irq + + # Common parts of receive API + + def start_recv(self, timeout_ms=None, continuous=False, rx_length=0xFF): + # Start receiving. + # + # Part of common low-level modem API, see README.md for usage. + if continuous and timeout_ms is not None: + raise ValueError # these two options are mutually exclusive + + if timeout_ms is not None: + self._rx = time.ticks_add(time.ticks_ms(), timeout_ms) + else: + self._rx = True + + self._rx_continuous = continuous + self._rx_length = rx_length + + if self._ant_sw and not self._tx: + # this is guarded on 'not self._tx' as the subclass will not immediately + # start receiving if a send is in progress. + self._ant_sw.rx() + + def poll_recv(self, rx_packet=None): + # Should be called while a receive is in progress: + # + # Part of common low-level modem API, see README.md for usage. + # + # This function may alter the state of the modem - it will clear + # RX interrupts, it may read out a packet from the FIFO, and it + # may resume receiving if the modem has gone to standby but receive + # should resume. + + if self._rx is False: + # Not actually receiving... + return False + + if self._tx: + # Actually sending, this has to complete before we + # resume receiving, but we'll indicate that we are still receiving. + # + # (It's not harmful to fall through here and check flags anyhow, but + # it is a little wasteful if an interrupt has just triggered + # poll_send() as well.) + return True + + packet = None + + flags = self._get_irq() + + if _DEBUG and flags: + print("RX flags {:#x}".format(flags)) + if flags & self._IRQ_RX_COMPLETE: + # There is a small potential for race conditions here in continuous + # RX mode. If packets are received rapidly and the call to this + # function delayed, then a ValidHeader interrupt (for example) might + # have already set for a second packet which is being received now, + # and clearing it will mark the second packet as invalid. + # + # However it's necessary in continuous mode as interrupt flags don't + # self-clear in the modem otherwise (for example, if a CRC error IRQ + # bit sets then it stays set on the next packet, even if that packet + # has a valid CRC.) + self._clear_irq(flags) + ok = self._rx_flags_success(flags) + if not ok: + # If a non-valid receive happened, increment the CRC error counter + self.crc_errors += 1 + if ok or self.rx_crc_error: + # Successfully received a valid packet (or configured to return all packets) + packet = self._read_packet(rx_packet, flags) + if not self._rx_continuous: + # Done receiving now + self._end_recv() + + # _check_recv() will return True if a receive is ongoing and hasn't timed out, + # and also manages resuming any modem receive if needed + # + # We need to always call check_recv(), but if we received a packet then this is what + # we should return to the caller. + res = self._check_recv() + return packet or res + + def _end_recv(self): + # Utility function to clear the receive state + self._rx = False + if self._ant_sw: + self._ant_sw.idle() + + def _check_recv(self): + # Internal function to automatically call start_recv() + # again if a receive has been interrupted and the host + # needs to start it again. + # + # Return True if modem is still receiving (or sending, but will + # resume receiving after send finishes). + + if not self._rx: + return False # Not receiving, nothing to do + + if not self.is_idle(): + return True # Radio is already sending or receiving + + rx = self._rx + + timeout_ms = None + if isinstance(rx, int): # timeout is set + timeout_ms = time.ticks_diff(rx, time.ticks_ms()) + if timeout_ms <= 0: + # Timed out in software, nothing to resume + self._end_recv() + if _DEBUG: + print("Timed out in software timeout_ms={}".format(timeout_ms)) + schedule(self._radio_isr, None) # "soft irq" to unblock anything waiting on the interrupt event + return False + + if _DEBUG: + print("Resuming receive timeout_ms={} continuous={} rx_length={}".format(timeout_ms, self._rx_continuous, self._rx_length)) + + self.start_recv(timeout_ms, self._rx_continuous, self._rx_length) + + # restore the previous version of _rx so ticks_ms deadline can't + # slowly creep forward each time this happens + self._rx = rx + + return True + + # Common parts of send API + + def poll_send(self): + # Check the ongoing send state. + # + # Returns one of: + # + # - True if a send is ongoing and the caller + # should call again. + # - False if no send is ongoing. + # - An int value exactly one time per transmission, the first time + # poll_send() is called after a send ends. In this case it + # is the time.ticks_ms() timestamp of the time that the send completed. + # + # Note this function only returns an int value one time (the first time it + # is called after send completes). + # + # Part of common low-level modem API, see README.md for usage. + if not self._tx: + return False + + ticks_ms = self._get_last_irq() + + if not (self._get_irq() & self._IRQ_TX_COMPLETE): + # Not done. If the host and modem get out + # of sync here, or the caller doesn't follow the sequence of + # send operations exactly, then can end up in a situation here + # where the modem has stopped sending and has gone to Standby, + # so _IRQ_TX_DONE is never set. + # + # For now, leaving this for the caller to do correctly. But if it becomes an issue then + # we can call _get_mode() here as well and check the modem is still in a TX mode. + return True + + self._clear_irq() + + self._tx = False + + if self._ant_sw: + self._ant_sw.idle() + + # The modem just finished sending, so start receiving again if needed + self._check_recv() + + return ticks_ms + + +class RxPacket(bytearray): + # A class to hold a packet received from a LoRa modem. + # + # The base class is bytearray, which represents the packet payload, + # allowing RxPacket objects to be passed anywhere that bytearrays are + # accepted. + # + # Some additional properties are set on the object to store metadata about + # the received packet. + def __init__(self, payload, ticks_ms=None, snr=None, rssi=None, valid_crc=True): + super().__init__(payload) + self.ticks_ms = ticks_ms + self.snr = snr + self.rssi = rssi + self.valid_crc = valid_crc + + def __repr__(self): + return "{}({}, {}, {}, {}, {})".format( + "RxPacket", + repr(bytes(self)), # This is a bit wasteful, but gets us b'XYZ' rather than "bytearray(b'XYZ')" + self.ticks_ms, + self.snr, + self.rssi, + self.valid_crc, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/modem.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/modem.pyi new file mode 100644 index 000000000..fae4d35d3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/modem.pyi @@ -0,0 +1,54 @@ +from _typeshed import Incomplete +from micropython import const as const + +_DEBUG: bool + +def _clamp(v, vmin, vmax): ... +def _flag(value, condition): ... + +class ConfigError(ValueError): + def __init__(self, field) -> None: ... + +class BaseModem: + _ant_sw: Incomplete + _irq_callback: Incomplete + _rf_freq_hz: int + _sf: int + _bw_hz: int + _coding_rate: int + _crc_en: bool + _implicit_header: bool + _preamble_len: int + crc_errors: int + rx_crc_error: bool + _rx: bool + _rx_continuous: bool + _rx_length: Incomplete + _tx: bool + _last_irq: Incomplete + _invert_iq: Incomplete + def __init__(self, ant_sw) -> None: ... + def standby(self) -> None: ... + def _get_t_sym_us(self): ... + def _get_ldr_en(self): ... + def _get_pa_ramp_val(self, lora_cfg, supported): ... + def _symbol_offsets(self): ... + def get_n_symbols_x4(self, payload_len): ... + def get_time_on_air_us(self, payload_len): ... + def _radio_isr(self, _) -> None: ... + def irq_triggered(self): ... + def set_irq_callback(self, callback) -> None: ... + def _get_last_irq(self): ... + def start_recv(self, timeout_ms=None, continuous: bool = False, rx_length: int = 255) -> None: ... + def poll_recv(self, rx_packet=None): ... + def _end_recv(self) -> None: ... + def _check_recv(self): ... + def poll_send(self): ... + +class RxPacket(bytearray): + ticks_ms: Incomplete + snr: Incomplete + rssi: Incomplete + valid_crc: Incomplete + def __init__(self, payload, ticks_ms=None, snr=None, rssi=None, valid_crc: bool = True) -> None: ... + def __repr__(self) -> str: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/stm32wl5.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/stm32wl5.py new file mode 100644 index 000000000..05c2e6161 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/stm32wl5.py @@ -0,0 +1,136 @@ +# MicroPython LoRa STM32WL55 embedded sub-ghz radio driver +# MIT license; Copyright (c) 2022 Angus Gratton +# +# This driver is essentially an embedded SX1262 with a custom internal interface block. +# Requires the stm module in MicroPython to be compiled with STM32WL5 subghz radio support. +# +# LoRa is a registered trademark or service mark of Semtech Corporation or its affiliates. +from machine import Pin, SPI +import stm +from . import sx126x +from micropython import const + +_CMD_CLR_ERRORS = 0x07 + +_REG_OCP = 0x8E7 + +# Default antenna switch config is as per Nucleo WL-55 board. See UM2592 Fig 18. +# Possible to work with other antenna switch board configurations by passing +# different ant_sw_class arguments to the modem, any class that creates an object with rx/tx + + +class NucleoWL55RFConfig: + def __init__(self): + self._FE_CTRL = (Pin(x, mode=Pin.OUT) for x in ("C4", "C5", "C3")) + + def _set_fe_ctrl(self, values): + for pin, val in zip(self._FE_CTRL, values): + pin(val) + + def rx(self): + self._set_fe_ctrl((1, 0, 1)) + + def tx(self, hp): + self._set_fe_ctrl((0 if hp else 1, 1, 1)) + + def idle(self): + pass + + +class DIO1: + # Dummy DIO1 "Pin" wrapper class to pass to the _SX126x class + def irq(self, handler, _): + stm.subghz_irq(handler) + + +class _WL55SubGhzModem(sx126x._SX126x): + # Don't construct this directly, construct lora.WL55SubGhzModem or lora.AsyncWL55SubGHzModem + def __init__( + self, + lora_cfg=None, + tcxo_millivolts=1700, + ant_sw=NucleoWL55RFConfig, + ): + self._hp = False + + if ant_sw == NucleoWL55RFConfig: + # To avoid the default argument being an object instance + ant_sw = NucleoWL55RFConfig() + + super().__init__( + # RM0453 7.2.13 says max 16MHz, but this seems more stable + SPI("SUBGHZ", baudrate=8_000_000), + stm.subghz_cs, + stm.subghz_is_busy, + DIO1(), + False, # dio2_rf_sw + tcxo_millivolts, # dio3_tcxo_millivolts + 10_000, # dio3_tcxo_start_time_us, first time after POR is quite long + None, # reset + lora_cfg, + ant_sw, + ) + + def _clear_errors(self): + # A weird difference between STM32WL55 and SX1262, WL55 only takes one + # parameter byte for the Clr_Error() command compared to two on SX1262. + # The bytes are always zero in both cases. + # + # (Not clear if sending two bytes will also work always/sometimes, but + # sending one byte to SX1262 definitely does not work! + self._cmd("BB", _CMD_CLR_ERRORS, 0x00) + + def _clear_irq(self, clear_bits=0xFFFF): + super()._clear_irq(clear_bits) + # SUBGHZ Radio IRQ requires manual re-enabling after interrupt + stm.subghz_irq(self._radio_isr) + + def _tx_hp(self): + # STM32WL5 supports both High and Low Power antenna pins depending on tx_ant setting + return self._hp + + def _get_pa_tx_params(self, output_power, tx_ant): + # Given an output power level in dBm and the tx_ant setting (if any), + # return settings for SetPaConfig and SetTxParams. + # + # ST document RM0453 Set_PaConfig() reference and accompanying Table 35 + # show values that are an exact superset of the SX1261 and SX1262 + # available values, depending on which antenna pin is to be + # used. Therefore, call either modem's existing _get_pa_tx_params() + # function depending on the current tx_ant setting (default is low + # power). + + if tx_ant is not None: + # Note: currently HP antenna power output is less than it should be, + # due to some (unknown) bug. + self._hp = tx_ant == "PA_BOOST" + + # Update the OCP register to match the maximum power level + self._reg_write(_REG_OCP, 0x38 if self._hp else 0x18) + + if self._hp: + return sx126x._SX1262._get_pa_tx_params(self, output_power, tx_ant) + else: + return sx126x._SX1261._get_pa_tx_params(self, output_power, tx_ant) + + +# Define the actual modem classes that use the SyncModem & AsyncModem "mixin-like" classes +# to create sync and async variants. + +try: + from .sync_modem import SyncModem + + class WL55SubGhzModem(_WL55SubGhzModem, SyncModem): + pass + +except ImportError: + pass + +try: + from .async_modem import AsyncModem + + class AsyncWL55SubGhzModem(_WL55SubGhzModem, AsyncModem): + pass + +except ImportError: + pass diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/stm32wl5.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/stm32wl5.pyi new file mode 100644 index 000000000..6e0e3d85c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/stm32wl5.pyi @@ -0,0 +1,30 @@ +from . import sx126x as sx126x +from .async_modem import AsyncModem as AsyncModem +from .sync_modem import SyncModem as SyncModem +from _typeshed import Incomplete +from micropython import const as const + +_CMD_CLR_ERRORS: int +_REG_OCP: int + +class NucleoWL55RFConfig: + _FE_CTRL: Incomplete + def __init__(self) -> None: ... + def _set_fe_ctrl(self, values) -> None: ... + def rx(self) -> None: ... + def tx(self, hp) -> None: ... + def idle(self) -> None: ... + +class DIO1: + def irq(self, handler, _) -> None: ... + +class _WL55SubGhzModem(sx126x._SX126x): + _hp: bool + def __init__(self, lora_cfg=None, tcxo_millivolts: int = 1700, ant_sw=...) -> None: ... + def _clear_errors(self) -> None: ... + def _clear_irq(self, clear_bits: int = 65535) -> None: ... + def _tx_hp(self): ... + def _get_pa_tx_params(self, output_power, tx_ant): ... + +class WL55SubGhzModem(_WL55SubGhzModem, SyncModem): ... +class AsyncWL55SubGhzModem(_WL55SubGhzModem, AsyncModem): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sx126x.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sx126x.py new file mode 100644 index 000000000..3a03f9030 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sx126x.py @@ -0,0 +1,890 @@ +# MicroPython LoRa SX126x (SX1261, SX1262) driver +# MIT license; Copyright (c) 2023 Angus Gratton +# +# LoRa is a registered trademark or service mark of Semtech Corporation or its affiliates. +# +# In comments, abbreviation "DS" = Semtech SX1261/62 Datasheet Rev 2.1 (December 2021) +import struct +import time +from micropython import const +from machine import Pin +from .modem import BaseModem, ConfigError, RxPacket, _clamp, _flag + +# Set _DEBUG to True to print all SPI commands sent to the device, and all responses, +# plus a few additional pieces of information. +_DEBUG = False + +_REG_RXGAINCR = 0x8AC # Reset value 0x94 +_REG_LSYNCRH = 0x740 +_REG_LSYNCRL = 0x741 + +_CMD_CFG_DIO_IRQ = 0x08 # args: IrqMask, Irq1Mask, Irq2Mask,. Irq3Mask +_CMD_CLR_ERRORS = 0x07 +_CMD_CLR_IRQ_STATUS = 0x02 # no args +_CMD_GET_ERROR = 0x17 +_CMD_GET_IRQ_STATUS = 0x12 # args: (r) Status, IrqStatus +_CMD_GET_RX_BUFFER_STATUS = 0x13 # args: (r) Status, RxPayloadLength, RxBufferPointer +# NOTE: _CMD_GET_STATUS seems to have an issue, see _get_status() function below. +_CMD_GET_STATUS = 0xC0 # args: (r) Status +_CMD_GET_PACKET_STATUS = 0x14 +_CMD_READ_REGISTER = 0x1D # args: addr (2b), status, (r) Data0 ... DataN +_CMD_READ_BUFFER = 0x1E # args: Offset, (r) Status, Data0 ... DataN +_CMD_SET_BUFFER_BASE_ADDRESS = 0x8F # args: TxBaseAddr, RxBaseAddr +_CMD_SET_MODULATION_PARAMS = 0x8B # args (LoRa): Sf, Bw, Cr, Ldro +_CMD_SET_PACKET_PARAMS = const(0x8C) # args (LoRa): PbLength, HeaderType, PayloadLength, CrcType, InvertIQ +_CMD_SET_PACKET_TYPE = 0x8A # args: PktType +_CMD_SET_PA_CONFIG = 0x95 # args: PaDutyCycle, HpMax, HpSel, 0x01 +_CMD_SET_RF_FREQUENCY = 0x86 # args: RfFreg +_CMD_SET_RX = 0x82 # args: Timeout +_CMD_SET_SLEEP = 0x84 # args: SleepCfg +_CMD_SET_STANDBY = 0x80 # args: StandbyCfg +_CMD_SET_DIO3_AS_TCXO_CTRL = 0x97 # args: Trim, Timeout (3b) +_CMD_SET_DIO2_AS_RF_SWITCH_CTRL = 0x9D +_CMD_SET_TX = 0x83 # args: Timeout +_CMD_SET_TX_PARAMS = 0x8E # args: Power, RampTime +_CMD_WRITE_BUFFER = 0x0E # args: Offset, Data0 ... DataN +_CMD_WRITE_REGISTER = 0x0D # args: Addr, Data0 ... Data N + +_CMD_CALIBRATE = 0x89 +_CMD_CALIBRATE_IMAGE = 0x98 + +_STATUS_MODE_MASK = 0x7 << 4 +_STATUS_MODE_SHIFT = 4 +_STATUS_MODE_STANDBY_RC = 0x2 +_STATUS_MODE_STANDBY_HSE32 = 0x3 +_STATUS_MODE_FS = 0x4 +_STATUS_MODE_RX = 0x5 +_STATUS_MODE_TX = 0x6 + +_STATUS_CMD_MASK = 0x6 # bits 1-3, bit 0 is reserved +_STATUS_CMD_SHIFT = 1 +_STATUS_CMD_DATA_AVAIL = 0x2 +_STATUS_CMD_TIMEOUT = 0x3 +_STATUS_CMD_ERROR = 0x4 +_STATUS_CMD_EXEC_FAIL = 0x5 +_STATUS_CMD_TX_COMPLETE = 0x6 + +_CFG_SF_MIN = 6 # inclusive +_CFG_SF_MAX = 12 # inclusive + +_IRQ_TX_DONE = 1 << 0 +_IRQ_RX_DONE = 1 << 1 +_IRQ_PREAMBLE_DETECTED = 1 << 2 +_IRQ_SYNC_DETECTED = 1 << 3 +_IRQ_HEADER_VALID = 1 << 4 +_IRQ_HEADER_ERR = 1 << 5 +_IRQ_CRC_ERR = 1 << 6 +_IRQ_CAD_DONE = 1 << 7 +_IRQ_CAD_DETECTED = 1 << 8 +_IRQ_TIMEOUT = 1 << 9 + +# Register values +_REG_IQ_POLARITY_SETUP = 0x0736 +_REG_RX_GAIN = 0x08AC +_REG_RTC_CTRL = 0x0902 # DS 15.3 has a typo on this value! Confirmed from Semtech driver +_REG_EVT_CLR = 0x0944 +_REG_EVT_CLR_MASK = 0x02 + +# IRQs the driver cares about when receiving +_IRQ_DRIVER_RX_MASK = const(_IRQ_RX_DONE | _IRQ_TIMEOUT | _IRQ_CRC_ERR | _IRQ_HEADER_ERR) + + +# Except when entering/waking from sleep, typical busy period <105us (ref RM0453 Table 33) +# +# However, if dio3_tcxo_start_time_us is set then can take a longer +# time to become valid, so a field is set on the modem object with the full timeout. +# +# In any case, timeouts here are to catch broken/bad hardware or massive driver +# bugs rather than commonplace issues. +# +_CMD_BUSY_TIMEOUT_BASE_US = 7000 + +# Datasheet says 3.5ms needed to run a full Calibrate command (all blocks), +# however testing shows it can be as much as as 18ms. +_CALIBRATE_TYPICAL_TIME_US = 3500 +_CALIBRATE_TIMEOUT_US = 30000 + +# Magic value used by SetRx command to indicate a continuous receive +_CONTINUOUS_TIMEOUT_VAL = 0xFFFFFF + + +class _SX126x(BaseModem): + # common IRQ masks used by the base class functions + _IRQ_RX_COMPLETE = _IRQ_RX_DONE | _IRQ_TIMEOUT + _IRQ_TX_COMPLETE = _IRQ_TX_DONE + + # Common base class for SX1261, SX1262 and (pending) STM32WL55. These are all basically + # the same except for which PA ranges are supported + # + # Don't construct this directly, construct lora.SX1261, lora.SX1262, lora.AsyncSX1261 + # or lora.AsyncSX1262 + def __init__( + self, + spi, + cs, + busy, + dio1, + dio2_rf_sw, + dio3_tcxo_millivolts, + dio3_tcxo_start_time_us, + reset, + lora_cfg, + ant_sw, + ): + super().__init__(ant_sw) + + self._spi = spi + self._cs = cs + self._busy = busy + self._sleep = True # assume the radio is in sleep mode to start, will wake on _cmd + self._dio1 = dio1 + + if hasattr(busy, "init"): + busy.init(Pin.IN) + if hasattr(cs, "init"): + cs.init(Pin.OUT, value=1) + if hasattr(dio1, "init"): + dio1.init(Pin.IN) + + self._busy_timeout = _CMD_BUSY_TIMEOUT_BASE_US + (dio3_tcxo_start_time_us if dio3_tcxo_millivolts else 0) + + self._buf_view = memoryview(bytearray(9)) # shared buffer for commands + + # These settings are kept in the object (as can't read them back from the modem) + self._output_power = 14 + self._bw = 125 + assert self._bw_hz == 125000 # This field is set in base class, must match self._bw + + # RampTime register value + # 0x02 is 40us, default value appears undocumented but this is the SX1276 default + self._ramp_val = 0x02 + + # Configure the SX126x at least once after reset + self._configured = False + + if reset: + # If the caller supplies a reset pin argument, reset the radio + reset.init(Pin.OUT, value=0) + time.sleep_ms(1) + reset(1) + time.sleep_ms(5) + else: + # Otherwise, at least put the radio to a known state + self._cmd("BB", _CMD_SET_STANDBY, 0) # STDBY_RC mode, not ready for TCXO yet + + status = self._get_status() + if (status[0] != _STATUS_MODE_STANDBY_RC and status[0] != _STATUS_MODE_STANDBY_HSE32) or (status[1] > 1): + # This check exists to determine that the SPI settings and modem + # selection are correct. Otherwise it's possible for the driver to + # run for quite some time before it detects an invalid response. + raise RuntimeError("Invalid initial status {}.".format(status)) + + if dio2_rf_sw: + self._cmd("BB", _CMD_SET_DIO2_AS_RF_SWITCH_CTRL, 1) + + if dio3_tcxo_millivolts: + # Enable TCXO power via DIO3, if enabled + # + # timeout register is set in units of 15.625us each, use integer math + # to calculate and round up: + timeout = (dio3_tcxo_start_time_us * 1000 + 15624) // 15625 + if timeout < 0 or timeout > 1 << 24: + raise ValueError("{} out of range".format("dio3_tcxo_start_time_us")) + if dio3_tcxo_millivolts < 1600 or dio3_tcxo_millivolts > 3300: + raise ValueError("{} out of range".format("dio3_tcxo_millivolts")) + dv = dio3_tcxo_millivolts // 100 # 16 to 33 + tcxo_trim_lookup = ( + 16, + 17, + 18, + 22, + 24, + 27, + 30, + 33, + ) # DS Table 13-35 + while dv not in tcxo_trim_lookup: + dv -= 1 + reg_tcxo_trim = tcxo_trim_lookup.index(dv) + + self._cmd(">BI", _CMD_SET_DIO3_AS_TCXO_CTRL, (reg_tcxo_trim << 24) + timeout) + time.sleep_ms(15) + # As per DS 13.3.6 SetDIO3AsTCXOCtrl, should expect error + # value 0x20 "XOSC_START_ERR" to be flagged as XOSC has only just + # started now. So clear it. + self._clear_errors() + + self._check_error() + + # If DIO1 is set, mask in just the IRQs that the driver may need to be + # interrupted by. This is important because otherwise an unrelated IRQ + # can trigger the ISR and may not be reset by the driver, leaving DIO1 high. + # + # If DIO1 is not set, all IRQs can stay masked which is the power-on state. + if dio1: + # Note: we set both Irq mask and DIO1 mask to the same value, which is redundant + # (one could be 0xFFFF) but may save a few bytes of bytecode. + self._cmd( + ">BHHHH", + _CMD_CFG_DIO_IRQ, + (_IRQ_RX_DONE | _IRQ_TX_DONE | _IRQ_TIMEOUT), # IRQ mask + (_IRQ_RX_DONE | _IRQ_TX_DONE | _IRQ_TIMEOUT), # DIO1 mask + 0x0, # DIO2Mask, not used + 0x0, # DIO3Mask, not used + ) + dio1.irq(self._radio_isr, Pin.IRQ_RISING) + + self._clear_irq() + + self._cmd("BB", _CMD_SET_PACKET_TYPE, 1) # LoRa + + if lora_cfg: + self.configure(lora_cfg) + + def sleep(self, warm_start=True): + # Put the modem into sleep mode. Driver will wake the modem automatically the next + # time an operation starts, or call standby() to wake it manually. + # + # If the warm_start parameter is False (non-default) then the modem will + # lose all settings on wake. The only way to use this parameter value is + # to destroy this modem object after calling it, and then instantiate a new + # modem object on wake. + # + self._check_error() # check errors before going to sleep because we clear on wake + self.standby() # save some code size, this clears the driver's rx/tx state + self._cmd("BB", _CMD_SET_SLEEP, _flag(1 << 2, warm_start)) + self._sleep = True + + def _standby(self): + # Send the command for standby mode. + # + # **Don't call this function directly, call standby() instead.** + # + # (This private version doesn't update the driver's internal state.) + self._cmd("BB", _CMD_SET_STANDBY, 1) # STDBY_XOSC mode + self._clear_irq() # clear IRQs in case we just cancelled a send or receive + + def is_idle(self): + # Returns True if the modem is idle (either in standby or in sleep). + # + # Note this function can return True in the case where the modem has temporarily gone to + # standby but there's a receive configured in software that will resume receiving the next + # time poll_recv() or poll_send() is called. + if self._sleep: + return True # getting status wakes from sleep + mode, _ = self._get_status() + return mode in (_STATUS_MODE_STANDBY_HSE32, _STATUS_MODE_STANDBY_RC) + + def _wakeup(self): + # Wake the modem from sleep. This is called automatically the first + # time a modem command is sent after sleep() was called to put the modem to + # sleep. + # + # To manually wake the modem without initiating a new operation, call standby(). + self._cs(0) + time.sleep_us(20) + self._cs(1) + self._sleep = False + self._clear_errors() # Clear "XOSC failed to start" which will reappear at this time + self._check_error() # raise an exception if any other error appears + + def _decode_status(self, raw_status, check_errors=True): + # split the raw status, which often has reserved bits set, into the mode value + # and the command status value + mode = (raw_status & _STATUS_MODE_MASK) >> _STATUS_MODE_SHIFT + cmd = (raw_status & _STATUS_CMD_MASK) >> _STATUS_CMD_SHIFT + if check_errors and cmd in (_STATUS_CMD_EXEC_FAIL, _STATUS_CMD_ERROR): + raise RuntimeError("Status {},{} indicates command error".format(mode, cmd)) + return (mode, cmd) + + def _get_status(self): + # Issue the GetStatus command and return the decoded status of (mode + # value, command status) + # + # Due to what appears to be a silicon bug, we send GetIrqStatus here + # instead of GetStatus. It seems that there is some specific sequence + # where sending command GetStatus to the chip immediately after SetRX + # (mode 5) will trip it it into an endless TX (mode 6) for no apparent + # reason! + # + # It doesn't seem to be timing dependent, all that's needed is that + # ordering (and the modem works fine otherwise). + # + # As a workaround we send the GetIrqStatus command and read an extra two + # bytes that are then ignored... + res = self._cmd("B", _CMD_GET_IRQ_STATUS, n_read=3)[0] + return self._decode_status(res) + + def _check_error(self): + # Raise a RuntimeError if the radio has reported an error state. + # + # Return the decoded status, otherwise. + res = self._cmd("B", _CMD_GET_ERROR, n_read=3) + status = self._decode_status(res[0], False) + op_error = (res[1] << 8) + res[2] + if op_error != 0: + raise RuntimeError("Internal radio Status {} OpError {:#x}".format(status, op_error)) + self._decode_status(res[0]) # raise an exception here if status shows an error + return status + + def _clear_errors(self): + # Clear any errors flagged in the modem + self._cmd(">BH", _CMD_CLR_ERRORS, 0) + + def _clear_irq(self, clear_bits=0xFFFF): + # Clear IRQs flagged in the modem + # + # By default, clears all IRQ bits. Otherwise, argument is the mask of bits to clear. + self._cmd(">BH", _CMD_CLR_IRQ_STATUS, clear_bits) + self._last_irq = None + + def _set_tx_ant(self, tx_ant): + # Only STM32WL55 allows switching tx_ant from LP to HP + raise ConfigError("tx_ant") + + def _symbol_offsets(self): + # Called from BaseModem.get_time_on_air_us(). + # + # This function provides a way to implement the different SF5 and SF6 in SX126x, + # by returning two offsets: one for the overall number of symbols, and one for the + # number of bits used to calculate the symbol length of the payload. + return (2, -8) if self._sf in (5, 6) else (0, 0) + + def configure(self, lora_cfg): + if self._rx is not False: + raise RuntimeError("Receiving") + + if "preamble_len" in lora_cfg: + self._preamble_len = lora_cfg["preamble_len"] + + self._invert_iq = [ + lora_cfg.get("invert_iq_rx", self._invert_iq[0]), + lora_cfg.get("invert_iq_tx", self._invert_iq[1]), + self._invert_iq[2], + ] + + if "freq_khz" in lora_cfg: + self._rf_freq_hz = int(lora_cfg["freq_khz"] * 1000) + rffreq = (self._rf_freq_hz << 25) // 32_000_000 # RF-PLL frequency = 32e^6 * RFFreq / 2^25 + if not rffreq: + raise ConfigError("freq_khz") # set to a value too low + self._cmd(">BI", _CMD_SET_RF_FREQUENCY, rffreq) + + if "syncword" in lora_cfg: + syncword = lora_cfg["syncword"] + if syncword < 0x100: + # "Translation from SX127x to SX126x : 0xYZ -> 0xY4Z4 : + # if you do not set the two 4 you might lose sensitivity" + # see + # https://www.thethingsnetwork.org/forum/t/should-private-lorawan-networks-use-a-different-sync-word/34496/15 + syncword = 0x0404 + ((syncword & 0x0F) << 4) + ((syncword & 0xF0) << 8) + self._cmd(">BHH", _CMD_WRITE_REGISTER, _REG_LSYNCRH, syncword) + + if not self._configured or any(key in lora_cfg for key in ("output_power", "pa_ramp_us", "tx_ant")): + pa_config_args, self._output_power = self._get_pa_tx_params( + lora_cfg.get("output_power", self._output_power), lora_cfg.get("tx_ant", None) + ) + self._cmd("BBBBB", _CMD_SET_PA_CONFIG, *pa_config_args) + + if "pa_ramp_us" in lora_cfg: + self._ramp_val = self._get_pa_ramp_val(lora_cfg, [10, 20, 40, 80, 200, 800, 1700, 3400]) + + self._cmd("BBB", _CMD_SET_TX_PARAMS, self._output_power, self._ramp_val) + + if not self._configured or any(key in lora_cfg for key in ("sf", "bw", "coding_rate")): + if "sf" in lora_cfg: + self._sf = lora_cfg["sf"] + if self._sf < _CFG_SF_MIN or self._sf > _CFG_SF_MAX: + raise ConfigError("sf") + + if "bw" in lora_cfg: + self._bw = lora_cfg["bw"] + + if "coding_rate" in lora_cfg: + self._coding_rate = lora_cfg["coding_rate"] + if self._coding_rate < 4 or self._coding_rate > 8: # 4/4 through 4/8, linearly + raise ConfigError("coding_rate") + + bw_val, self._bw_hz = { + "7.8": (0x00, 7800), + "10.4": (0x08, 10400), + "15.6": (0x01, 15600), + "20.8": (0x09, 20800), + "31.25": (0x02, 31250), + "41.7": (0x0A, 41700), + "62.5": (0x03, 62500), + "125": (0x04, 125000), + "250": (0x05, 250000), + "500": (0x06, 500000), + }[str(self._bw)] + + self._cmd( + "BBBBB", + _CMD_SET_MODULATION_PARAMS, + self._sf, + bw_val, + self._coding_rate - 4, # 4/4=0, 4/5=1, etc + self._get_ldr_en(), # Note: BaseModem.get_n_symbols_x4() depends on this logic + ) + + if "rx_boost" in lora_cfg: + # See DS Table 9-3 "Rx Gain Configuration" + self._reg_write(_REG_RX_GAIN, 0x96 if lora_cfg["rx_boost"] else 0x94) + + self._check_error() + self._configured = True + + def _invert_workaround(self, enable): + # Apply workaround for DS 15.4 Optimizing the Inverted IQ Operation + if self._invert_iq[2] != enable: + val = self._reg_read(_REG_IQ_POLARITY_SETUP) + val = (val & ~4) | _flag(4, enable) + self._reg_write(_REG_IQ_POLARITY_SETUP, val) + self._invert_iq[2] = enable + + def _get_irq(self): + # Get currently set IRQ bits. + irq_status = self._cmd("B", _CMD_GET_IRQ_STATUS, n_read=3) + status = self._decode_status(irq_status[0]) + flags = (irq_status[1] << 8) + irq_status[2] + if _DEBUG: + print("Status {} flags {:#x}".format(status, flags)) + return flags + + def calibrate(self): + # Send the Calibrate command to the radio to calibrate RC oscillators, PLL and ADC. + # + # See DS 13.1.12 Calibrate Function + + # calibParam 0xFE means to calibrate all blocks. + self._cmd("BB", _CMD_CALIBRATE, 0xFE) + + time.sleep_us(_CALIBRATE_TYPICAL_TIME_US) + + # a falling edge of BUSY indicates calibration is done + self._wait_not_busy(_CALIBRATE_TIMEOUT_US) + + def calibrate_image(self): + # Send the CalibrateImage command to the modem to improve reception in + # the currently configured frequency band. + # + # See DS 9.2.1 Image Calibration for Specified Frequency Bands + # and 13.1.13 CalibrateImage + + mhz = self._rf_freq_hz // 1_000_000 + if 430 <= mhz <= 440: + args = 0x6B6F + elif 470 <= mhz <= 510: + args = 0x7581 + elif 779 <= mhz <= 787: + args = 0xC1C5 + elif 863 <= mhz <= 870: + args = 0xD7DB + elif 902 <= mhz <= 928: + args = 0xE1E9 + else: + # DS says "Contact your Semtech representative for the other optimal + # calibration settings outside of the given frequency bands" + raise ValueError + + self._cmd(">BH", _CMD_CALIBRATE_IMAGE, args) + + # Can't find anythign in Datasheet about how long image calibration + # takes or exactly how it signals completion. Assuming it will be + # similar to _CMD_CALIBRATE. + self._wait_not_busy(_CALIBRATE_TIMEOUT_US) + + def start_recv(self, timeout_ms=None, continuous=False, rx_length=0xFF): + # Start receiving. + # + # Part of common low-level modem API, see README.md for usage. + super().start_recv(timeout_ms, continuous, rx_length) # sets _rx + + if self._tx: + # Send is in progress and has priority, _check_recv() will start recv + # once send finishes (caller needs to call poll_send() for this to happen.) + if _DEBUG: + print("Delaying receive until send completes") + return self._dio1 + + # Put the modem in a known state. It's possible a different + # receive was in progress, this prevent anything changing while + # we set up the new receive + self._standby() # calling private version to keep driver state as-is + + # Allocate the full FIFO for RX + self._cmd("BBB", _CMD_SET_BUFFER_BASE_ADDRESS, 0xFF, 0x0) + + self._cmd( + ">BHBBBB", + _CMD_SET_PACKET_PARAMS, + self._preamble_len, + self._implicit_header, + rx_length, # PayloadLength, only used in implicit header mode + self._crc_en, # CRCType, only used in implicit header mode + self._invert_iq[0], # InvertIQ + ) + self._invert_workaround(self._invert_iq[0]) + + if continuous: + timeout = _CONTINUOUS_TIMEOUT_VAL + elif timeout_ms is not None: + timeout = max(1, timeout_ms * 64) # units of 15.625us + else: + timeout = 0 # Single receive mode, no timeout + + self._cmd(">BBH", _CMD_SET_RX, timeout >> 16, timeout) # 24 bits + + return self._dio1 + + def poll_recv(self, rx_packet=None): + old_rx = self._rx + rx = super().poll_recv(rx_packet) + + if rx is not True and old_rx is not False and isinstance(old_rx, int): + # Receiving has just stopped, and a timeout was previously set. + # + # Workaround for errata DS 15.3 "Implicit Header Mode Timeout Behaviour", + # which recommends to add the following after "ANY Rx with Timeout active sequence" + self._reg_write(_REG_RTC_CTRL, 0x00) + self._reg_write(_REG_EVT_CLR, self._reg_read(_REG_EVT_CLR) | _REG_EVT_CLR_MASK) + + return rx + + def _rx_flags_success(self, flags): + # Returns True if IRQ flags indicate successful receive. + # Specifically, from the bits in _IRQ_DRIVER_RX_MASK: + # - _IRQ_RX_DONE must be set + # - _IRQ_TIMEOUT must not be set + # - _IRQ_CRC_ERR must not be set + # - _IRQ_HEADER_ERR must not be set + # + # (Note: this is a function because the result for SX1276 depends on + # current config, but the result is constant here.) + return flags & _IRQ_DRIVER_RX_MASK == _IRQ_RX_DONE + + def _read_packet(self, rx_packet, flags): + # Private function to read received packet (RxPacket object) from the + # modem, if there is one. + # + # Called from poll_recv() function, which has already checked the IRQ flags + # and verified a valid receive happened. + + ticks_ms = self._get_last_irq() + + res = self._cmd("B", _CMD_GET_RX_BUFFER_STATUS, n_read=3) + rx_payload_len = res[1] + rx_buffer_ptr = res[2] # should be 0 + + if rx_packet is None or len(rx_packet) != rx_payload_len: + rx_packet = RxPacket(rx_payload_len) + + self._cmd("BB", _CMD_READ_BUFFER, rx_buffer_ptr, n_read=1, read_buf=rx_packet) + + pkt_status = self._cmd("B", _CMD_GET_PACKET_STATUS, n_read=4) + + rx_packet.ticks_ms = ticks_ms + # SNR units are dB * 4 (signed) + rx_packet.rssi, rx_packet.snr = struct.unpack("xBbx", pkt_status) + rx_packet.rssi //= -2 # RSSI, units: dBm + rx_packet.crc_error = (flags & _IRQ_CRC_ERR) != 0 + + return rx_packet + + def prepare_send(self, packet): + # Prepare modem to start sending. Should be followed by a call to start_send() + # + # Part of common low-level modem API, see README.md for usage. + if len(packet) > 255: + raise ConfigError("packet too long") + + # Put the modem in a known state. Any current receive is suspended at this point, + # but calling _check_recv() will resume it later. + self._standby() # calling private version to keep driver state as-is + + self._check_error() + + # Set the board antenna for correct TX mode + if self._ant_sw: + self._ant_sw.tx(self._tx_hp()) + + self._last_irq = None + + self._cmd( + ">BHBBBB", + _CMD_SET_PACKET_PARAMS, + self._preamble_len, + self._implicit_header, + len(packet), + self._crc_en, + self._invert_iq[1], # _invert_iq_tx + ) + self._invert_workaround(self._invert_iq[1]) + + # Allocate the full FIFO for TX + self._cmd("BBB", _CMD_SET_BUFFER_BASE_ADDRESS, 0x0, 0xFF) + self._cmd("BB", _CMD_WRITE_BUFFER, 0x0, write_buf=packet) + + # Workaround for DS 15.1 Modulation Quality with 500 kHZ LoRa Bandwidth + # ... apparently this needs to be done "*before each packet transmission*" + if self._bw_hz == 500_000: + self._reg_write(0x0889, self._reg_read(0x0889) & 0xFB) + else: + self._reg_write(0x0889, self._reg_read(0x0889) | 0x04) + + def start_send(self): + # Actually start a send that was loaded by calling prepare_send(). + # + # This is split into a separate function to allow more precise timing. + # + # The driver doesn't verify the caller has done the right thing here, the + # modem will no doubt do something weird if prepare_send() was not called! + # + # Part of common low-level modem API, see README.md for usage. + + # Currently we don't pass any TX timeout argument to the modem1, + # which the datasheet ominously offers as "security" for the Host MCU if + # the send doesn't start for some reason. + + self._cmd("BBBB", _CMD_SET_TX, 0x0, 0x0, 0x0) + + if _DEBUG: + print("status {}".format(self._get_status())) + self._check_error() + + self._tx = True + + return self._dio1 + + def _wait_not_busy(self, timeout_us): + # Wait until the radio de-asserts the busy line + start = time.ticks_us() + ticks_diff = 0 + while self._busy(): + ticks_diff = time.ticks_diff(time.ticks_us(), start) + if ticks_diff > timeout_us: + raise RuntimeError("BUSY timeout", timeout_us) + time.sleep_us(1) + if _DEBUG and ticks_diff > 105: + # By default, debug log any busy time that takes longer than the + # datasheet-promised Typical 105us (this happens when starting the 32MHz oscillator, + # if it's turned on and off by the modem, and maybe other times.) + print(f"BUSY {ticks_diff}us") + + def _cmd(self, fmt, *write_args, n_read=0, write_buf=None, read_buf=None): + # Execute an SX1262 command + # fmt - Format string suitable for use with struct.pack. First item should be 'B' and + # corresponds to the command opcode. + # write_args - Arguments suitable for struct.pack using fmt. First argument should be a + # command opcode byte. + # + # Optional arguments: + # write_buf - Extra buffer to write from (for FIFO writes). Mutually exclusive with n_read + # or read_buf. + # n_read - Number of result bytes to read back at end + # read_buf - Extra buffer to read into (for FIFO reads) + # + # Returns None if n_read==0, otherwise a memoryview of length n_read which points into a + # shared buffer (buffer will be clobbered on next call to _cmd!) + if self._sleep: + self._wakeup() + + # Ensure "busy" from previously issued command has de-asserted. Usually this will + # have happened well before _cmd() is called again. + self._wait_not_busy(self._busy_timeout) + + # Pack write_args into slice of _buf_view memoryview of correct length + wrlen = struct.calcsize(fmt) + assert n_read + wrlen <= len(self._buf_view) # if this fails, make _buf bigger! + struct.pack_into(fmt, self._buf_view, 0, *write_args) + buf = self._buf_view[: (wrlen + n_read)] + + if _DEBUG: + print(">>> {}".format(buf[:wrlen].hex())) + if write_buf: + print(">>> {}".format(write_buf.hex())) + self._cs(0) + self._spi.write_readinto(buf, buf) + if write_buf: + self._spi.write(write_buf) # Used by _CMD_WRITE_BUFFER only + if read_buf: + self._spi.readinto(read_buf, 0xFF) # Used by _CMD_READ_BUFFER only + self._cs(1) + + if n_read > 0: + res = self._buf_view[wrlen : (wrlen + n_read)] # noqa: E203 + if _DEBUG: + print("<<< {}".format(res.hex())) + return res + + def _reg_read(self, addr): + return self._cmd(">BHB", _CMD_READ_REGISTER, addr, 0, n_read=1)[0] + + def _reg_write(self, addr, val): + return self._cmd(">BHB", _CMD_WRITE_REGISTER, addr, val & 0xFF) + + +class _SX1262(_SX126x): + # Don't construct this directly, construct lora.SX1262 or lora.AsyncSX1262 + def __init__( + self, + spi, + cs, + busy, + dio1=None, + dio2_rf_sw=True, + dio3_tcxo_millivolts=None, + dio3_tcxo_start_time_us=1000, + reset=None, + lora_cfg=None, + ant_sw=None, + ): + super().__init__( + spi, + cs, + busy, + dio1, + dio2_rf_sw, + dio3_tcxo_millivolts, + dio3_tcxo_start_time_us, + reset, + lora_cfg, + ant_sw, + ) + + # Apply workaround for DS 15.2 "Better Resistance of the SX1262 Tx to Antenna Mismatch + self._reg_write(0x8D8, self._reg_read(0x8D8) | 0x1E) + + def _tx_hp(self): + # SX1262 has High Power only (deviceSel==0) + return True + + def _get_pa_tx_params(self, output_power, tx_ant): + # Given an output power level in dB, return a 2-tuple: + # - First item is the 3 arguments for SetPaConfig command + # - Second item is the power level argument value for SetTxParams command. + # + # DS 13.1.14.1 "PA Optimal Settings" gives optimally efficient + # values for output power +22, +20, +17, +14 dBm and "these changes make + # the use of nominal power either sub-optimal or unachievable" (hence it + # recommends setting +22dBm nominal TX Power for all these). + # + # However the modem supports output power as low as -9dBm, and there's + # no explanation in the datasheet of how to best set other output power + # levels. + # + # Semtech's own driver (sx126x.c in LoRaMac-node) only ever executes + # SetPaConfig with the values shown in the datasheet for +22dBm, and + # then executes SetTxParams with power set to the nominal value in + # dBm. + # + # Try for best of both worlds here: If the caller requests an "Optimal" + # value, use the datasheet values. Otherwise set nominal power only as + # per Semtech's driver. + output_power = int(_clamp(output_power, -9, 22)) + + DEFAULT = (0x4, 0x7, 0x0, 0x1) + OPTIMAL = { + 22: (DEFAULT, 22), + 20: ((0x3, 0x5, 0x0, 0x1), 22), + 17: ((0x2, 0x3, 0x0, 0x1), 22), + 14: ((0x2, 0x2, 0x0, 0x1), 22), + } + if output_power in OPTIMAL: + # Datasheet optimal values + return OPTIMAL[output_power] + else: + # Nominal values, as per Semtech driver + return (DEFAULT, output_power & 0xFF) + + +class _SX1261(_SX126x): + # Don't construct this directly, construct lora.SX1261, or lora.AsyncSX1261 + def __init__( + self, + spi, + cs, + busy, + dio1=None, + dio2_rf_sw=True, + dio3_tcxo_millivolts=None, + dio3_tcxo_start_time_us=1000, + reset=None, + lora_cfg=None, + ant_sw=None, + ): + super().__init__( + spi, + cs, + busy, + dio1, + dio2_rf_sw, + dio3_tcxo_millivolts, + dio3_tcxo_start_time_us, + reset, + lora_cfg, + ant_sw, + ) + + def _tx_hp(self): + # SX1261 has Low Power only (deviceSel==1) + return False + + def _get_pa_tx_params(self, output_power, tx_ant): + # Given an output power level in dB, return a 2-tuple: + # - First item is the 3 arguments for SetPaConfig command + # - Second item is the power level argument value for SetTxParams command. + # + # As noted above for SX1262, DS 13.1.14.1 "PA Optimal Settings" + # gives optimally efficient values for output power +15, +14, +10 dBm + # but nothing specific to the other power levels (down to -17dBm). + # + # Therefore do the same as for SX1262 to set optimal values if known, nominal otherwise. + output_power = _clamp(int(output_power), -17, 15) + + DEFAULT = (0x4, 0x0, 0x1, 0x1) + OPTIMAL = { + 15: ((0x06, 0x0, 0x1, 0x1), 14), + 14: (DEFAULT, 14), + 10: ((0x1, 0x0, 0x1, 0x1), 13), + } + + if output_power == 15 and self._rf_freq_hz < 400_000_000: + # DS 13.1.14.1 has Note that PaDutyCycle is limited to 0x4 below 400MHz, + # so disallow the 15dBm optimal setting. + output_power = 14 + + if output_power in OPTIMAL: + # Datasheet optimal values + return OPTIMAL[output_power] + else: + # Nominal values, as per Semtech driver + return (DEFAULT, output_power & 0xFF) + + +# Define the actual modem classes that use the SyncModem & AsyncModem "mixin-like" classes +# to create sync and async variants. + +try: + from .sync_modem import SyncModem + + class SX1261(_SX1261, SyncModem): + pass + + class SX1262(_SX1262, SyncModem): + pass + +except ImportError: + pass + +try: + from .async_modem import AsyncModem + + class AsyncSX1261(_SX1261, AsyncModem): + pass + + class AsyncSX1262(_SX1262, AsyncModem): + pass + +except ImportError: + pass diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sx126x.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sx126x.pyi new file mode 100644 index 000000000..092396b9b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sx126x.pyi @@ -0,0 +1,160 @@ +from .async_modem import AsyncModem as AsyncModem +from .modem import BaseModem as BaseModem, ConfigError as ConfigError, RxPacket as RxPacket, _clamp as _clamp, _flag as _flag +from .sync_modem import SyncModem as SyncModem +from _typeshed import Incomplete + +_DEBUG: bool +_REG_RXGAINCR: int +_REG_LSYNCRH: int +_REG_LSYNCRL: int +_CMD_CFG_DIO_IRQ: int +_CMD_CLR_ERRORS: int +_CMD_CLR_IRQ_STATUS: int +_CMD_GET_ERROR: int +_CMD_GET_IRQ_STATUS: int +_CMD_GET_RX_BUFFER_STATUS: int +_CMD_GET_STATUS: int +_CMD_GET_PACKET_STATUS: int +_CMD_READ_REGISTER: int +_CMD_READ_BUFFER: int +_CMD_SET_BUFFER_BASE_ADDRESS: int +_CMD_SET_MODULATION_PARAMS: int +_CMD_SET_PACKET_PARAMS: Incomplete +_CMD_SET_PACKET_TYPE: int +_CMD_SET_PA_CONFIG: int +_CMD_SET_RF_FREQUENCY: int +_CMD_SET_RX: int +_CMD_SET_SLEEP: int +_CMD_SET_STANDBY: int +_CMD_SET_DIO3_AS_TCXO_CTRL: int +_CMD_SET_DIO2_AS_RF_SWITCH_CTRL: int +_CMD_SET_TX: int +_CMD_SET_TX_PARAMS: int +_CMD_WRITE_BUFFER: int +_CMD_WRITE_REGISTER: int +_CMD_CALIBRATE: int +_CMD_CALIBRATE_IMAGE: int +_STATUS_MODE_MASK: Incomplete +_STATUS_MODE_SHIFT: int +_STATUS_MODE_STANDBY_RC: int +_STATUS_MODE_STANDBY_HSE32: int +_STATUS_MODE_FS: int +_STATUS_MODE_RX: int +_STATUS_MODE_TX: int +_STATUS_CMD_MASK: int +_STATUS_CMD_SHIFT: int +_STATUS_CMD_DATA_AVAIL: int +_STATUS_CMD_TIMEOUT: int +_STATUS_CMD_ERROR: int +_STATUS_CMD_EXEC_FAIL: int +_STATUS_CMD_TX_COMPLETE: int +_CFG_SF_MIN: int +_CFG_SF_MAX: int +_IRQ_TX_DONE: Incomplete +_IRQ_RX_DONE: Incomplete +_IRQ_PREAMBLE_DETECTED: Incomplete +_IRQ_SYNC_DETECTED: Incomplete +_IRQ_HEADER_VALID: Incomplete +_IRQ_HEADER_ERR: Incomplete +_IRQ_CRC_ERR: Incomplete +_IRQ_CAD_DONE: Incomplete +_IRQ_CAD_DETECTED: Incomplete +_IRQ_TIMEOUT: Incomplete +_REG_IQ_POLARITY_SETUP: int +_REG_RX_GAIN: int +_REG_RTC_CTRL: int +_REG_EVT_CLR: int +_REG_EVT_CLR_MASK: int +_IRQ_DRIVER_RX_MASK: Incomplete +_CMD_BUSY_TIMEOUT_BASE_US: int +_CALIBRATE_TYPICAL_TIME_US: int +_CALIBRATE_TIMEOUT_US: int +_CONTINUOUS_TIMEOUT_VAL: int + +class _SX126x(BaseModem): + _IRQ_RX_COMPLETE = _IRQ_RX_DONE | _IRQ_TIMEOUT + _IRQ_TX_COMPLETE = _IRQ_TX_DONE + _spi: Incomplete + _cs: Incomplete + _busy: Incomplete + _sleep: bool + _dio1: Incomplete + _busy_timeout: Incomplete + _buf_view: Incomplete + _output_power: int + _bw: int + _ramp_val: int + _configured: bool + def __init__(self, spi, cs, busy, dio1, dio2_rf_sw, dio3_tcxo_millivolts, dio3_tcxo_start_time_us, reset, lora_cfg, ant_sw) -> None: ... + def sleep(self, warm_start: bool = True) -> None: ... + def _standby(self) -> None: ... + def is_idle(self): ... + def _wakeup(self) -> None: ... + def _decode_status(self, raw_status, check_errors: bool = True): ... + def _get_status(self): ... + def _check_error(self): ... + def _clear_errors(self) -> None: ... + _last_irq: Incomplete + def _clear_irq(self, clear_bits: int = 65535) -> None: ... + def _set_tx_ant(self, tx_ant) -> None: ... + def _symbol_offsets(self): ... + _preamble_len: Incomplete + _invert_iq: Incomplete + _rf_freq_hz: Incomplete + _sf: Incomplete + _coding_rate: Incomplete + def configure(self, lora_cfg) -> None: ... + def _invert_workaround(self, enable) -> None: ... + def _get_irq(self): ... + def calibrate(self) -> None: ... + def calibrate_image(self) -> None: ... + def start_recv(self, timeout_ms=None, continuous: bool = False, rx_length: int = 255): ... + def poll_recv(self, rx_packet=None): ... + def _rx_flags_success(self, flags): ... + def _read_packet(self, rx_packet, flags): ... + def prepare_send(self, packet) -> None: ... + _tx: bool + def start_send(self): ... + def _wait_not_busy(self, timeout_us) -> None: ... + def _cmd(self, fmt, *write_args, n_read: int = 0, write_buf=None, read_buf=None): ... + def _reg_read(self, addr): ... + def _reg_write(self, addr, val): ... + +class _SX1262(_SX126x): + def __init__( + self, + spi, + cs, + busy, + dio1=None, + dio2_rf_sw: bool = True, + dio3_tcxo_millivolts=None, + dio3_tcxo_start_time_us: int = 1000, + reset=None, + lora_cfg=None, + ant_sw=None, + ) -> None: ... + def _tx_hp(self): ... + def _get_pa_tx_params(self, output_power, tx_ant): ... + +class _SX1261(_SX126x): + def __init__( + self, + spi, + cs, + busy, + dio1=None, + dio2_rf_sw: bool = True, + dio3_tcxo_millivolts=None, + dio3_tcxo_start_time_us: int = 1000, + reset=None, + lora_cfg=None, + ant_sw=None, + ) -> None: ... + def _tx_hp(self): ... + def _get_pa_tx_params(self, output_power, tx_ant): ... + +class SX1261(_SX1261, SyncModem): ... +class SX1262(_SX1262, SyncModem): ... +class AsyncSX1261(_SX1261, AsyncModem): ... +class AsyncSX1262(_SX1262, AsyncModem): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sync_modem.py b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sync_modem.py new file mode 100644 index 000000000..585ae2cb4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sync_modem.py @@ -0,0 +1,86 @@ +# MicroPython LoRa synchronous modem driver +# MIT license; Copyright (c) 2023 Angus Gratton +# +# LoRa is a registered trademark or service mark of Semtech Corporation or its affiliates. + +import machine +import time + + +class SyncModem: + # Mixin-like base class that provides synchronous modem send and recv + # functions + # + # + # Don't instantiate this class directly, instantiate one of the 'AsyncXYZ' + # modem classes defined in the lora module. + # + # These are intended for simple applications. They block the caller until + # the modem operation is complete, and don't support interleaving send + # and receive. + + def _after_init(self): + pass # Needed for AsyncModem but not SyncModem + + def send(self, packet, tx_at_ms=None): + # Send the given packet (byte sequence), + # and return once transmission of the packet is complete. + # + # Returns a timestamp (result of time.ticks_ms()) when the packet + # finished sending. + self.prepare_send(packet) + + # If the caller specified a timestamp to start transmission at, wait until + # that time before triggering the send + if tx_at_ms is not None: + time.sleep_ms(max(0, time.ticks_diff(tx_at_ms, time.ticks_ms()))) + + will_irq = self.start_send() # ... and go! + + # sleep for the expected send time before checking if send has ended + time.sleep_ms(self.get_time_on_air_us(len(packet)) // 1000) + + tx = True + while tx is True: + self._sync_wait(will_irq) + tx = self.poll_send() + return tx + + def recv(self, timeout_ms=None, rx_length=0xFF, rx_packet=None): + # Attempt to a receive a single LoRa packet, timeout after timeout_ms milliseconds + # or wait indefinitely if no timeout is supplied (default). + # + # Returns an instance of RxPacket or None if the radio timed out while receiving. + # + # Optional rx_length argument is only used if lora_cfg["implict_header"] == True + # (not the default) and holds the length of the payload to receive. + # + # Optional rx_packet argument can be an existing instance of RxPacket + # which will be reused to save allocations, but only if the received packet + # is the same length as the rx_packet packet. If the length is different, a + # new RxPacket instance is allocated and returned. + will_irq = self.start_recv(timeout_ms, False, rx_length) + rx = True + while rx is True: + self._sync_wait(will_irq) + rx = self.poll_recv(rx_packet) + return rx or None + + def _sync_wait(self, will_irq): + # For synchronous usage, block until an interrupt occurs or we time out + if will_irq: + for n in range(100): + machine.idle() + # machine.idle() wakes up very often, so don't actually return + # unless _radio_isr ran already. The outer for loop is so the + # modem is still polled occasionally to + # avoid the possibility an IRQ was lost somewhere. + # + # None of this is very efficient, power users should either use + # async or call the low-level API manually with better + # port-specific sleep configurations, in order to get the best + # efficiency. + if self.irq_triggered(): + break + else: + time.sleep_ms(1) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sync_modem.pyi b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sync_modem.pyi new file mode 100644 index 000000000..e85035b2f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/lora/sync_modem.pyi @@ -0,0 +1,5 @@ +class SyncModem: + def _after_init(self) -> None: ... + def send(self, packet, tx_at_ms=None): ... + def recv(self, timeout_ms=None, rx_length: int = 255, rx_packet=None): ... + def _sync_wait(self, will_irq) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/modules.json new file mode 100644 index 000000000..7f0ca4d21 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/NUCLEO_WL55/modules.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "NUCLEO_WL55", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "lora/__init__.py", + "module": "__init__" + }, + { + "file": "lora/modem.py", + "module": "modem" + }, + { + "file": "lora/stm32wl5.py", + "module": "stm32wl5" + }, + { + "file": "lora/sx126x.py", + "module": "sx126x" + }, + { + "file": "lora/sync_modem.py", + "module": "sync_modem" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/modules.json new file mode 100644 index 000000000..83ef4caeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "OLIMEX_E407", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OLIMEX_E407/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/__init__.py new file mode 100644 index 000000000..3e3b6038a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/__init__.py @@ -0,0 +1,32 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +from .device import Device, DeviceDisconnectedError +from .core import log_info, log_warn, log_error, GattError, config, stop + +try: + from .peripheral import advertise +except: + log_info("Peripheral support disabled") + +try: + from .central import scan +except: + log_info("Central support disabled") + +try: + from .server import ( + Service, + Characteristic, + BufferedCharacteristic, + Descriptor, + register_services, + ) +except: + log_info("GATT server support disabled") + + +ADDR_PUBLIC = 0 +ADDR_RANDOM = 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/__init__.pyi new file mode 100644 index 000000000..ddce380e0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/__init__.pyi @@ -0,0 +1,9 @@ +from .central import scan as scan +from .core import GattError as GattError, config as config, log_error as log_error, log_warn as log_warn, stop as stop +from .device import Device as Device, DeviceDisconnectedError as DeviceDisconnectedError +from .peripheral import advertise as advertise +from .server import BufferedCharacteristic as BufferedCharacteristic, Characteristic as Characteristic, Descriptor as Descriptor, Service as Service, register_services as register_services +from micropython import const as const + +ADDR_PUBLIC: int +ADDR_RANDOM: int diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/central.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/central.py new file mode 100644 index 000000000..0b9772efb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/central.py @@ -0,0 +1,305 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_SCAN_RESULT = 5 +_IRQ_SCAN_DONE = 6 + +_IRQ_PERIPHERAL_CONNECT = 7 +_IRQ_PERIPHERAL_DISCONNECT = 8 + +_ADV_IND = 0 +_ADV_DIRECT_IND = 1 +_ADV_SCAN_IND = 2 +_ADV_NONCONN_IND = 3 +_SCAN_RSP = 4 + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_SHORT_NAME = 0x08 +_ADV_TYPE_UUID16_INCOMPLETE = 0x2 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_INCOMPLETE = 0x4 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_INCOMPLETE = 0x6 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + + +# Keep track of the active scanner so IRQs can be delivered to it. +_active_scanner = None + + +# Set of devices that are waiting for the peripheral connect IRQ. +_connecting = set() + + +def _central_irq(event, data): + # Send results and done events to the active scanner instance. + if event == _IRQ_SCAN_RESULT: + addr_type, addr, adv_type, rssi, adv_data = data + if not _active_scanner: + return + _active_scanner._queue.append((addr_type, bytes(addr), adv_type, rssi, bytes(adv_data))) + _active_scanner._event.set() + elif event == _IRQ_SCAN_DONE: + if not _active_scanner: + return + _active_scanner._done = True + _active_scanner._event.set() + + # Peripheral connect must be in response to a pending connection, so find + # it in the pending connection set. + elif event == _IRQ_PERIPHERAL_CONNECT: + conn_handle, addr_type, addr = data + + for d in _connecting: + if d.addr_type == addr_type and d.addr == addr: + # Allow connect() to complete. + connection = d._connection + connection._conn_handle = conn_handle + connection._event.set() + break + + # Find the active device connection for this connection handle. + elif event == _IRQ_PERIPHERAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _central_shutdown(): + global _active_scanner, _connecting + _active_scanner = None + _connecting = set() + + +register_irq_handler(_central_irq, _central_shutdown) + + +# Cancel an in-progress scan. +async def _cancel_pending(): + if _active_scanner: + await _active_scanner.cancel() + + +# Start connecting to a peripheral. +# Call device.connect() rather than using method directly. +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us): + device = connection.device + if device in _connecting: + return + + # Enable BLE and cancel in-progress scans. + ensure_active() + await _cancel_pending() + + # Allow the connected IRQ to find the device by address. + _connecting.add(device) + + # Event will be set in the connected IRQ, and then later + # re-used to notify disconnection. + connection._event = connection._event or asyncio.ThreadSafeFlag() + + try: + with DeviceTimeout(None, timeout_ms): + ble.gap_connect( + device.addr_type, + device.addr, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Wait for the connected IRQ. + await connection._event.wait() + assert connection._conn_handle is not None + + # Register connection handle -> device. + DeviceConnection._connected[connection._conn_handle] = connection + finally: + # After timeout, don't hold a reference and ignore future events. + _connecting.remove(device) + + +# Represents a single device that has been found during a scan. The scan +# iterator will return the same ScanResult instance multiple times as its data +# changes (i.e. changing RSSI or advertising data). +class ScanResult: + def __init__(self, device): + self.device = device + self.adv_data = None + self.resp_data = None + self.rssi = None + self.connectable = False + + # New scan result available, return true if it changes our state. + def _update(self, adv_type, rssi, adv_data): + updated = False + + if rssi != self.rssi: + self.rssi = rssi + updated = True + + if adv_type in (_ADV_IND, _ADV_NONCONN_IND): + if adv_data != self.adv_data: + self.adv_data = adv_data + self.connectable = adv_type == _ADV_IND + updated = True + elif adv_type == _ADV_SCAN_IND: + if adv_data != self.adv_data and self.resp_data: + updated = True + self.adv_data = adv_data + elif adv_type == _SCAN_RSP and adv_data: + if adv_data != self.resp_data: + self.resp_data = adv_data + updated = True + + return updated + + def __str__(self): + return "Scan result: {} {}".format(self.device, self.rssi) + + # Gets all the fields for the specified types. + def _decode_field(self, *adv_type): + # Advertising payloads are repeated packets of the following form: + # 1 byte data length (N + 1) + # 1 byte type (see constants below) + # N bytes type-specific data + for payload in (self.adv_data, self.resp_data): + if not payload: + continue + i = 0 + while i + 1 < len(payload): + if payload[i + 1] in adv_type: + yield payload[i + 2 : i + payload[i] + 1] + i += 1 + payload[i] + + # Returns the value of the complete (or shortened) advertised name, if available. + def name(self): + for n in self._decode_field(_ADV_TYPE_NAME, _ADV_TYPE_SHORT_NAME): + return str(n, "utf-8") if n else "" + + # Generator that enumerates the service UUIDs that are advertised. + def services(self): + for uuid_len, codes in ( + (2, (_ADV_TYPE_UUID16_INCOMPLETE, _ADV_TYPE_UUID16_COMPLETE)), + (4, (_ADV_TYPE_UUID32_INCOMPLETE, _ADV_TYPE_UUID32_COMPLETE)), + (16, (_ADV_TYPE_UUID128_INCOMPLETE, _ADV_TYPE_UUID128_COMPLETE)), + ): + for u in self._decode_field(*codes): + for i in range(0, len(u), uuid_len): + yield bluetooth.UUID(u[i : i + uuid_len]) + + # Generator that returns (manufacturer_id, data) tuples. + def manufacturer(self, filter=None): + for u in self._decode_field(_ADV_TYPE_MANUFACTURER): + if len(u) < 2: + continue + m = struct.unpack(" None: ... +def _central_shutdown() -> None: ... +async def _cancel_pending() -> None: ... +async def _connect(connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us) -> None: ... + +class ScanResult: + device: Incomplete + adv_data: Incomplete + resp_data: Incomplete + rssi: Incomplete + connectable: bool + def __init__(self, device) -> None: ... + def _update(self, adv_type, rssi, adv_data): ... + def __str__(self) -> str: ... + def _decode_field(self, *adv_type) -> Generator[Incomplete]: ... + def name(self): ... + def services(self) -> Generator[Incomplete]: ... + def manufacturer(self, filter=None) -> Generator[Incomplete]: ... + +class scan: + _queue: Incomplete + _event: Incomplete + _done: bool + _results: Incomplete + _duration_ms: Incomplete + _interval_us: Incomplete + _window_us: Incomplete + _active: Incomplete + def __init__(self, duration_ms, interval_us=None, window_us=None, active: bool = False) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + async def cancel(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/client.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/client.py new file mode 100644 index 000000000..125213f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/client.py @@ -0,0 +1,444 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import asyncio +import struct + +import bluetooth + +from .core import ble, GattError, register_irq_handler +from .device import DeviceConnection + + +_IRQ_GATTC_SERVICE_RESULT = 9 +_IRQ_GATTC_SERVICE_DONE = 10 +_IRQ_GATTC_CHARACTERISTIC_RESULT = 11 +_IRQ_GATTC_CHARACTERISTIC_DONE = 12 +_IRQ_GATTC_DESCRIPTOR_RESULT = 13 +_IRQ_GATTC_DESCRIPTOR_DONE = 14 +_IRQ_GATTC_READ_RESULT = 15 +_IRQ_GATTC_READ_DONE = 16 +_IRQ_GATTC_WRITE_DONE = 17 +_IRQ_GATTC_NOTIFY = 18 +_IRQ_GATTC_INDICATE = 19 + +_CCCD_UUID = 0x2902 +_CCCD_NOTIFY = 1 +_CCCD_INDICATE = 2 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + + +# Forward IRQs directly to static methods on the type that handles them and +# knows how to map handles to instances. Note: We copy all uuid and data +# params here for safety, but a future optimisation might be able to avoid +# these copies in a few places. +def _client_irq(event, data): + if event == _IRQ_GATTC_SERVICE_RESULT: + conn_handle, start_handle, end_handle, uuid = data + ClientDiscover._discover_result(conn_handle, start_handle, end_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_SERVICE_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: + conn_handle, end_handle, value_handle, properties, uuid = data + ClientDiscover._discover_result(conn_handle, end_handle, value_handle, properties, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_DESCRIPTOR_RESULT: + conn_handle, dsc_handle, uuid = data + ClientDiscover._discover_result(conn_handle, dsc_handle, bluetooth.UUID(uuid)) + elif event == _IRQ_GATTC_DESCRIPTOR_DONE: + conn_handle, status = data + ClientDiscover._discover_done(conn_handle, status) + elif event == _IRQ_GATTC_READ_RESULT: + conn_handle, value_handle, char_data = data + ClientCharacteristic._read_result(conn_handle, value_handle, bytes(char_data)) + elif event == _IRQ_GATTC_READ_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._read_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_WRITE_DONE: + conn_handle, value_handle, status = data + ClientCharacteristic._write_done(conn_handle, value_handle, status) + elif event == _IRQ_GATTC_NOTIFY: + conn_handle, value_handle, notify_data = data + ClientCharacteristic._on_notify(conn_handle, value_handle, bytes(notify_data)) + elif event == _IRQ_GATTC_INDICATE: + conn_handle, value_handle, indicate_data = data + ClientCharacteristic._on_indicate(conn_handle, value_handle, bytes(indicate_data)) + + +register_irq_handler(_client_irq, None) + + +# Async generator for discovering services, characteristics, descriptors. +class ClientDiscover: + def __init__(self, connection, disc_type, parent, timeout_ms, *args): + self._connection = connection + + # Each result IRQ will append to this. + self._queue = [] + # This will be set by the done IRQ. + self._status = None + + # Tell the generator to process new events. + self._event = asyncio.ThreadSafeFlag() + + # Must implement the _start_discovery static method. Instances of this + # type are returned by __anext__. + self._disc_type = disc_type + + # This will be the connection for a service discovery, and the service for a characteristic discovery. + self._parent = parent + + # Timeout for the discovery process. + # TODO: Not implemented. + self._timeout_ms = timeout_ms + + # Additional arguments to pass to the _start_discovery method on disc_type. + self._args = args + + async def _start(self): + if self._connection._discover: + # TODO: cancel existing? (e.g. perhaps they didn't let the loop run to completion) + raise ValueError("Discovery in progress") + + # Tell the connection that we're the active discovery operation (the IRQ only gives us conn_handle). + self._connection._discover = self + # Call the appropriate ubluetooth.BLE method. + self._disc_type._start_discovery(self._parent, *self._args) + + def __aiter__(self): + return self + + async def __anext__(self): + if self._connection._discover != self: + # Start the discovery if necessary. + await self._start() + + # Keep returning items from the queue until the status is set by the + # done IRQ. + while True: + while self._queue: + return self._disc_type(self._parent, *self._queue.pop()) + if self._status is not None: + self._connection._discover = None + raise StopAsyncIteration + # Wait for more results to be added to the queue. + await self._event.wait() + + # Tell the active discovery instance for this connection to add a new result + # to the queue. + def _discover_result(conn_handle, *args): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._queue.append(args) + discover._event.set() + + # Tell the active discovery instance for this connection that it is complete. + def _discover_done(conn_handle, status): + if connection := DeviceConnection._connected.get(conn_handle, None): + if discover := connection._discover: + discover._status = status + discover._event.set() + + +# Represents a single service supported by a connection. Do not construct this +# class directly, instead use `async for service in connection.services([uuid])` or +# `await connection.service(uuid)`. +class ClientService: + def __init__(self, connection, start_handle, end_handle, uuid): + self.connection = connection + + # Used for characteristic discovery. + self._start_handle = start_handle + self._end_handle = end_handle + + # Allows comparison to a known uuid. + self.uuid = uuid + + def __str__(self): + return "Service: {} {} {}".format(self._start_handle, self._end_handle, self.uuid) + + # Search for a specific characteristic by uuid. + async def characteristic(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for characteristic in self.characteristics(uuid, timeout_ms): + if not result and characteristic.uuid == uuid: + # Keep first result. + result = characteristic + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for characteristic in service.characteristics(): + # Note: must allow the loop to run to completion. + def characteristics(self, uuid=None, timeout_ms=2000): + return ClientDiscover(self.connection, ClientCharacteristic, self, timeout_ms, uuid) + + # For ClientDiscover + def _start_discovery(connection, uuid=None): + ble.gattc_discover_services(connection._conn_handle, uuid) + + +class BaseClientCharacteristic: + def __init__(self, value_handle, properties, uuid): + # Used for read/write/notify ops. + self._value_handle = value_handle + + # Which operations are supported. + self.properties = properties + + # Allows comparison to a known uuid. + self.uuid = uuid + + if properties & _FLAG_READ: + # Fired for each read result and read done IRQ. + self._read_event = None + self._read_data = None + # Used to indicate that the read is complete. + self._read_status = None + + if (properties & _FLAG_WRITE) or (properties & _FLAG_WRITE_NO_RESPONSE): + # Fired for the write done IRQ. + self._write_event = None + # Used to indicate that the write is complete. + self._write_status = None + + # Register this value handle so events can find us. + def _register_with_connection(self): + self._connection()._characteristics[self._value_handle] = self + + # Map an incoming IRQ to an registered characteristic. + def _find(conn_handle, value_handle): + if connection := DeviceConnection._connected.get(conn_handle, None): + if characteristic := connection._characteristics.get(value_handle, None): + return characteristic + else: + # IRQ for a characteristic that we weren't expecting. e.g. + # notification when we're not waiting on notified(). + # TODO: This will happen on btstack, which doesn't give us + # value handle for the done event. + return None + + def _check(self, flag): + if not (self.properties & flag): + raise ValueError("Unsupported") + + # Issue a read to the characteristic. + async def read(self, timeout_ms=1000): + self._check(_FLAG_READ) + # Make sure this conn_handle/value_handle is known. + self._register_with_connection() + # This will be set by the done IRQ. + self._read_status = None + # This will be set by the result and done IRQs. Re-use if possible. + self._read_event = self._read_event or asyncio.ThreadSafeFlag() + + # Issue the read. + ble.gattc_read(self._connection()._conn_handle, self._value_handle) + + with self._connection().timeout(timeout_ms): + # The event will be set for each read result, then a final time for done. + while self._read_status is None: + await self._read_event.wait() + if self._read_status != 0: + raise GattError(self._read_status) + return self._read_data + + # Map an incoming result IRQ to a registered characteristic. + def _read_result(conn_handle, value_handle, data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_data = data + characteristic._read_event.set() + + # Map an incoming read done IRQ to a registered characteristic. + def _read_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._read_status = status + characteristic._read_event.set() + + async def write(self, data, response=None, timeout_ms=1000): + self._check(_FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE) + + # If the response arg is unset, then default it to true if we only support write-with-response. + if response is None: + p = self.properties + response = (p & _FLAG_WRITE) and not (p & _FLAG_WRITE_NO_RESPONSE) + + if response: + # Same as read. + self._register_with_connection() + self._write_status = None + self._write_event = self._write_event or asyncio.ThreadSafeFlag() + + # Issue the write. + ble.gattc_write(self._connection()._conn_handle, self._value_handle, data, response) + + if response: + with self._connection().timeout(timeout_ms): + # The event will be set for the write done IRQ. + await self._write_event.wait() + if self._write_status != 0: + raise GattError(self._write_status) + + # Map an incoming write done IRQ to a registered characteristic. + def _write_done(conn_handle, value_handle, status): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._write_status = status + characteristic._write_event.set() + + +# Represents a single characteristic supported by a service. Do not construct +# this class directly, instead use `async for characteristic in +# service.characteristics([uuid])` or `await service.characteristic(uuid)`. +class ClientCharacteristic(BaseClientCharacteristic): + def __init__(self, service, end_handle, value_handle, properties, uuid): + self.service = service + self.connection = service.connection + + # Used for descriptor discovery. If available, otherwise assume just + # past the value handle (enough for two descriptors without risking + # going into the next characteristic). + self._end_handle = end_handle if end_handle > value_handle else value_handle + 2 + + super().__init__(value_handle, properties, uuid) + + if properties & _FLAG_NOTIFY: + # Fired when a notification arrives. + self._notify_event = asyncio.ThreadSafeFlag() + # Data for the most recent notification. + self._notify_queue = deque((), 1) + if properties & _FLAG_INDICATE: + # Same for indications. + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_queue = deque((), 1) + + def __str__(self): + return "Characteristic: {} {} {} {}".format(self._end_handle, self._value_handle, self.properties, self.uuid) + + def _connection(self): + return self.service.connection + + # Search for a specific descriptor by uuid. + async def descriptor(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for descriptor in self.descriptors(timeout_ms): + if not result and descriptor.uuid == uuid: + # Keep first result. + result = descriptor + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for descriptor in characteristic.descriptors(): + # Note: must allow the loop to run to completion. + def descriptors(self, timeout_ms=2000): + return ClientDiscover(self.connection, ClientDescriptor, self, timeout_ms) + + # For ClientDiscover + def _start_discovery(service, uuid=None): + ble.gattc_discover_characteristics( + service.connection._conn_handle, + service._start_handle, + service._end_handle, + uuid, + ) + + # Helper for notified() and indicated(). + async def _notified_indicated(self, queue, event, timeout_ms): + # Ensure that events for this connection can route to this characteristic. + self._register_with_connection() + + # If the queue is empty, then we need to wait. However, if the queue + # has a single item, we also need to do a no-op wait in order to + # clear the event flag (because the queue will become empty and + # therefore the event should be cleared). + if len(queue) <= 1: + with self._connection().timeout(timeout_ms): + await event.wait() + + # Either we started > 1 item, or the wait completed successfully, return + # the front of the queue. + return queue.popleft() + + # Wait for the next notification. + # Will return immediately if a notification has already been received. + async def notified(self, timeout_ms=None): + self._check(_FLAG_NOTIFY) + return await self._notified_indicated(self._notify_queue, self._notify_event, timeout_ms) + + def _on_notify_indicate(self, queue, event, data): + # If we've gone from empty to one item, then wake something + # blocking on `await char.notified()` (or `await char.indicated()`). + wake = len(queue) == 0 + # Append the data. By default this is a deque with max-length==1, so it + # replaces. But if capture is enabled then it will append. + queue.append(data) + if wake: + # Queue is now non-empty. If something is waiting, it will be + # worken. If something isn't waiting right now, then a future + # caller to `await char.written()` will see the queue is + # non-empty, and wait on the event if it's going to empty the + # queue. + event.set() + + # Map an incoming notify IRQ to a registered characteristic. + def _on_notify(conn_handle, value_handle, notify_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._notify_queue, characteristic._notify_event, notify_data) + + # Wait for the next indication. + # Will return immediately if an indication has already been received. + async def indicated(self, timeout_ms=None): + self._check(_FLAG_INDICATE) + return await self._notified_indicated(self._indicate_queue, self._indicate_event, timeout_ms) + + # Map an incoming indicate IRQ to a registered characteristic. + def _on_indicate(conn_handle, value_handle, indicate_data): + if characteristic := ClientCharacteristic._find(conn_handle, value_handle): + characteristic._on_notify_indicate(characteristic._indicate_queue, characteristic._indicate_event, indicate_data) + + # Write to the Client Characteristic Configuration to subscribe to + # notify/indications for this characteristic. + async def subscribe(self, notify=True, indicate=False): + # Ensure that the generated notifications are dispatched in case the app + # hasn't awaited on notified/indicated yet. + self._register_with_connection() + if cccd := await self.descriptor(bluetooth.UUID(_CCCD_UUID)): + await cccd.write(struct.pack(" None: ... + +class ClientDiscover: + _connection: Incomplete + _queue: Incomplete + _status: Incomplete + _event: Incomplete + _disc_type: Incomplete + _parent: Incomplete + _timeout_ms: Incomplete + _args: Incomplete + def __init__(self, connection, disc_type, parent, timeout_ms, *args) -> None: ... + async def _start(self) -> None: ... + def __aiter__(self): ... + async def __anext__(self): ... + def _discover_result(conn_handle, *args) -> None: ... + def _discover_done(conn_handle, status) -> None: ... + +class ClientService: + connection: Incomplete + _start_handle: Incomplete + _end_handle: Incomplete + uuid: Incomplete + def __init__(self, connection, start_handle, end_handle, uuid) -> None: ... + def __str__(self) -> str: ... + async def characteristic(self, uuid, timeout_ms: int = 2000): ... + def characteristics(self, uuid=None, timeout_ms: int = 2000): ... + def _start_discovery(connection, uuid=None) -> None: ... + +class BaseClientCharacteristic: + _value_handle: Incomplete + properties: Incomplete + uuid: Incomplete + _read_event: Incomplete + _read_data: Incomplete + _read_status: Incomplete + _write_event: Incomplete + _write_status: Incomplete + def __init__(self, value_handle, properties, uuid) -> None: ... + def _register_with_connection(self) -> None: ... + def _find(conn_handle, value_handle): ... + def _check(self, flag) -> None: ... + async def read(self, timeout_ms: int = 1000): ... + def _read_result(conn_handle, value_handle, data) -> None: ... + def _read_done(conn_handle, value_handle, status) -> None: ... + async def write(self, data, response=None, timeout_ms: int = 1000) -> None: ... + def _write_done(conn_handle, value_handle, status) -> None: ... + +class ClientCharacteristic(BaseClientCharacteristic): + service: Incomplete + connection: Incomplete + _end_handle: Incomplete + _notify_event: Incomplete + _notify_queue: Incomplete + _indicate_event: Incomplete + _indicate_queue: Incomplete + def __init__(self, service, end_handle, value_handle, properties, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + async def descriptor(self, uuid, timeout_ms: int = 2000): ... + def descriptors(self, timeout_ms: int = 2000): ... + def _start_discovery(service, uuid=None) -> None: ... + async def _notified_indicated(self, queue, event, timeout_ms): ... + async def notified(self, timeout_ms=None): ... + def _on_notify_indicate(self, queue, event, data) -> None: ... + def _on_notify(conn_handle, value_handle, notify_data) -> None: ... + async def indicated(self, timeout_ms=None): ... + def _on_indicate(conn_handle, value_handle, indicate_data) -> None: ... + async def subscribe(self, notify: bool = True, indicate: bool = False) -> None: ... + +class ClientDescriptor(BaseClientCharacteristic): + characteristic: Incomplete + def __init__(self, characteristic, dsc_handle, uuid) -> None: ... + def __str__(self) -> str: ... + def _connection(self): ... + def _start_discovery(characteristic, uuid=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/core.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/core.py new file mode 100644 index 000000000..8daa2446a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/core.py @@ -0,0 +1,78 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +import bluetooth + + +log_level = 1 + + +def log_error(*args): + if log_level > 0: + print("[aioble] E:", *args) + + +def log_warn(*args): + if log_level > 1: + print("[aioble] W:", *args) + + +def log_info(*args): + if log_level > 2: + print("[aioble] I:", *args) + + +class GattError(Exception): + def __init__(self, status): + self._status = status + + +def ensure_active(): + if not ble.active(): + try: + from .security import load_secrets + + load_secrets() + except: + pass + ble.active(True) + + +def config(*args, **kwargs): + ensure_active() + return ble.config(*args, **kwargs) + + +# Because different functionality is enabled by which files are available the +# different modules can register their IRQ handlers and shutdown handlers +# dynamically. +_irq_handlers = [] +_shutdown_handlers = [] + + +def register_irq_handler(irq, shutdown): + if irq: + _irq_handlers.append(irq) + if shutdown: + _shutdown_handlers.append(shutdown) + + +def stop(): + ble.active(False) + for handler in _shutdown_handlers: + handler() + + +# Dispatch IRQs to the registered sub-modules. +def ble_irq(event, data): + log_info(event, data) + + for handler in _irq_handlers: + result = handler(event, data) + if result is not None: + return result + + +# TODO: Allow this to be injected. +ble = bluetooth.BLE() +ble.irq(ble_irq) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/core.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/core.pyi new file mode 100644 index 000000000..51440ac6e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/core.pyi @@ -0,0 +1,23 @@ +from _typeshed import Incomplete + +log_level: int + +def log_error(*args) -> None: ... +def log_warn(*args) -> None: ... +def log_info(*args) -> None: ... + +class GattError(Exception): + _status: Incomplete + def __init__(self, status) -> None: ... + +def ensure_active() -> None: ... +def config(*args, **kwargs): ... + +_irq_handlers: Incomplete +_shutdown_handlers: Incomplete + +def register_irq_handler(irq, shutdown) -> None: ... +def stop() -> None: ... +def ble_irq(event, data): ... + +ble: Incomplete diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/device.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/device.py new file mode 100644 index 000000000..ef32681d6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/device.py @@ -0,0 +1,304 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio +import binascii + +from .core import ble, register_irq_handler, log_error + + +_IRQ_MTU_EXCHANGED = 21 + + +# Raised by `with device.timeout()`. +class DeviceDisconnectedError(Exception): + pass + + +def _device_irq(event, data): + if event == _IRQ_MTU_EXCHANGED: + conn_handle, mtu = data + if device := DeviceConnection._connected.get(conn_handle, None): + device.mtu = mtu + if device._mtu_event: + device._mtu_event.set() + + +register_irq_handler(_device_irq, None) + + +# Context manager to allow an operation to be cancelled by timeout or device +# disconnection. Don't use this directly -- use `with connection.timeout(ms):` +# instead. +class DeviceTimeout: + def __init__(self, connection, timeout_ms): + self._connection = connection + self._timeout_ms = timeout_ms + + # We allow either (or both) connection and timeout_ms to be None. This + # allows this to be used either as a just-disconnect, just-timeout, or + # no-op. + + # This task is active while the operation is in progress. It sleeps + # until the timeout, and then cancels the working task. If the working + # task completes, __exit__ will cancel the sleep. + self._timeout_task = None + + # This is the task waiting for the actual operation to complete. + # Usually this is waiting on an event that will be set() by an IRQ + # handler. + self._task = asyncio.current_task() + + # Tell the connection that if it disconnects, it should cancel this + # operation (by cancelling self._task). + if connection: + connection._timeouts.append(self) + + async def _timeout_sleep(self): + try: + await asyncio.sleep_ms(self._timeout_ms) + except asyncio.CancelledError: + # The operation completed successfully and this timeout task was + # cancelled by __exit__. + return + + # The sleep completed, so we should trigger the timeout. Set + # self._timeout_task to None so that we can tell the difference + # between a disconnect and a timeout in __exit__. + self._timeout_task = None + self._task.cancel() + + def __enter__(self): + if self._timeout_ms: + # Schedule the timeout waiter. + self._timeout_task = asyncio.create_task(self._timeout_sleep()) + + def __exit__(self, exc_type, exc_val, exc_traceback): + # One of five things happened: + # 1 - The operation completed successfully. + # 2 - The operation timed out. + # 3 - The device disconnected. + # 4 - The operation failed for a different exception. + # 5 - The task was cancelled by something else. + + # Don't need the connection to tell us about disconnection anymore. + if self._connection: + self._connection._timeouts.remove(self) + + try: + if exc_type == asyncio.CancelledError: + # Case 2, we started a timeout and it's completed. + if self._timeout_ms and self._timeout_task is None: + raise asyncio.TimeoutError + + # Case 3, we have a disconnected device. + if self._connection and self._connection._conn_handle is None: + raise DeviceDisconnectedError + + # Case 5, something else cancelled us. + # Allow the cancellation to propagate. + return + + # Case 1 & 4. Either way, just stop the timeout task and let the + # exception (if case 4) propagate. + finally: + # In all cases, if the timeout is still running, cancel it. + if self._timeout_task: + self._timeout_task.cancel() + + +class Device: + def __init__(self, addr_type, addr): + # Public properties + self.addr_type = addr_type + self.addr = addr if len(addr) == 6 else binascii.unhexlify(addr.replace(":", "")) + self._connection = None + + def __eq__(self, rhs): + return self.addr_type == rhs.addr_type and self.addr == rhs.addr + + def __hash__(self): + return hash((self.addr_type, self.addr)) + + def __str__(self): + return "Device({}, {}{})".format( + "ADDR_PUBLIC" if self.addr_type == 0 else "ADDR_RANDOM", + self.addr_hex(), + ", CONNECTED" if self._connection else "", + ) + + def addr_hex(self): + return binascii.hexlify(self.addr, ":").decode() + + async def connect( + self, + timeout_ms=10000, + scan_duration_ms=None, + min_conn_interval_us=None, + max_conn_interval_us=None, + ): + if self._connection: + return self._connection + + # Forward to implementation in central.py. + from .central import _connect + + await _connect( + DeviceConnection(self), + timeout_ms, + scan_duration_ms, + min_conn_interval_us, + max_conn_interval_us, + ) + + # Start the device task that will clean up after disconnection. + self._connection._run_task() + return self._connection + + +class DeviceConnection: + # Global map of connection handle to active devices (for IRQ mapping). + _connected = {} + + def __init__(self, device): + self.device = device + device._connection = self + + self.encrypted = False + self.authenticated = False + self.bonded = False + self.key_size = False + self.mtu = None + + self._conn_handle = None + + # This event is fired by the IRQ both for connection and disconnection + # and controls the device_task. + self._event = asyncio.ThreadSafeFlag() + + # If we're waiting for a pending MTU exchange. + self._mtu_event = None + + # In-progress client discovery instance (e.g. services, chars, + # descriptors) used for IRQ mapping. + self._discover = None + # Map of value handle to characteristic (so that IRQs with + # conn_handle,value_handle can route to them). See + # ClientCharacteristic._find for where this is used. + self._characteristics = {} + + self._task = None + + # DeviceTimeout instances that are currently waiting on this device + # and need to be notified if disconnection occurs. + self._timeouts = [] + + # Fired by the encryption update event. + self._pair_event = None + + # Active L2CAP channel for this device. + # TODO: Support more than one concurrent channel. + self._l2cap_channel = None + + # While connected, this tasks waits for disconnection then cleans up. + async def device_task(self): + assert self._conn_handle is not None + + # Wait for the (either central or peripheral) disconnected irq. + await self._event.wait() + + # Mark the device as disconnected. + del DeviceConnection._connected[self._conn_handle] + self._conn_handle = None + self.device._connection = None + + # Cancel any in-progress operations on this device. + for t in self._timeouts: + t._task.cancel() + + def _run_task(self): + self._task = asyncio.create_task(self.device_task()) + + async def disconnect(self, timeout_ms=2000): + await self.disconnected(timeout_ms, disconnect=True) + + async def disconnected(self, timeout_ms=None, disconnect=False): + if not self.is_connected(): + return + + # The task must have been created after successful connection. + assert self._task + + if disconnect: + try: + ble.gap_disconnect(self._conn_handle) + except OSError as e: + log_error("Disconnect", e) + + with DeviceTimeout(None, timeout_ms): + await self._task + + # Retrieve a single service matching this uuid. + async def service(self, uuid, timeout_ms=2000): + result = None + # Make sure loop runs to completion. + async for service in self.services(uuid, timeout_ms): + if not result and service.uuid == uuid: + result = service + return result + + # Search for all services (optionally by uuid). + # Use with `async for`, e.g. + # async for service in device.services(): + # Note: must allow the loop to run to completion. + # TODO: disconnection / timeout + def services(self, uuid=None, timeout_ms=2000): + from .client import ClientDiscover, ClientService + + return ClientDiscover(self, ClientService, self, timeout_ms, uuid) + + async def pair(self, *args, **kwargs): + from .security import pair + + await pair(self, *args, **kwargs) + + def is_connected(self): + return self._conn_handle is not None + + # Use with `with` to simplify disconnection and timeout handling. + def timeout(self, timeout_ms): + return DeviceTimeout(self, timeout_ms) + + async def exchange_mtu(self, mtu=None, timeout_ms=1000): + if not self.is_connected(): + raise ValueError("Not connected") + + if mtu: + ble.config(mtu=mtu) + + self._mtu_event = self._mtu_event or asyncio.ThreadSafeFlag() + ble.gattc_exchange_mtu(self._conn_handle) + with self.timeout(timeout_ms): + await self._mtu_event.wait() + return self.mtu + + # Wait for a connection on an L2CAP connection-oriented-channel. + async def l2cap_accept(self, psm, mtu, timeout_ms=None): + from .l2cap import accept + + return await accept(self, psm, mtu, timeout_ms) + + # Attempt to connect to a listening device. + async def l2cap_connect(self, psm, mtu, timeout_ms=1000): + from .l2cap import connect + + return await connect(self, psm, mtu, timeout_ms) + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/device.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/device.pyi new file mode 100644 index 000000000..3afbc709f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/device.pyi @@ -0,0 +1,66 @@ +import types +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_MTU_EXCHANGED: int + +class DeviceDisconnectedError(Exception): ... + +def _device_irq(event, data) -> None: ... + +class DeviceTimeout: + _connection: Incomplete + _timeout_ms: Incomplete + _timeout_task: Incomplete + _task: Incomplete + def __init__(self, connection, timeout_ms) -> None: ... + async def _timeout_sleep(self) -> None: ... + def __enter__(self) -> None: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_traceback: types.TracebackType | None + ) -> None: ... + +class Device: + addr_type: Incomplete + addr: Incomplete + _connection: Incomplete + def __init__(self, addr_type, addr) -> None: ... + def __eq__(self, rhs): ... + def __hash__(self): ... + def __str__(self) -> str: ... + def addr_hex(self): ... + async def connect(self, timeout_ms: int = 10000, scan_duration_ms=None, min_conn_interval_us=None, max_conn_interval_us=None): ... + +class DeviceConnection: + _connected: Incomplete + device: Incomplete + encrypted: bool + authenticated: bool + bonded: bool + key_size: bool + mtu: Incomplete + _conn_handle: Incomplete + _event: Incomplete + _mtu_event: Incomplete + _discover: Incomplete + _characteristics: Incomplete + _task: Incomplete + _timeouts: Incomplete + _pair_event: Incomplete + _l2cap_channel: Incomplete + def __init__(self, device) -> None: ... + async def device_task(self) -> None: ... + def _run_task(self) -> None: ... + async def disconnect(self, timeout_ms: int = 2000) -> None: ... + async def disconnected(self, timeout_ms=None, disconnect: bool = False) -> None: ... + async def service(self, uuid, timeout_ms: int = 2000): ... + def services(self, uuid=None, timeout_ms: int = 2000): ... + async def pair(self, *args, **kwargs) -> None: ... + def is_connected(self): ... + def timeout(self, timeout_ms): ... + async def exchange_mtu(self, mtu=None, timeout_ms: int = 1000): ... + async def l2cap_accept(self, psm, mtu, timeout_ms=None): ... + async def l2cap_connect(self, psm, mtu, timeout_ms: int = 1000): ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/l2cap.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/l2cap.py new file mode 100644 index 000000000..7a75cb3cd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/l2cap.py @@ -0,0 +1,214 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import asyncio + +from .core import ble, log_error, register_irq_handler +from .device import DeviceConnection + + +_IRQ_L2CAP_ACCEPT = 22 +_IRQ_L2CAP_CONNECT = 23 +_IRQ_L2CAP_DISCONNECT = 24 +_IRQ_L2CAP_RECV = 25 +_IRQ_L2CAP_SEND_READY = 26 + + +# Once we start listening we're listening forever. (Limitation in NimBLE) +_listening = False + + +def _l2cap_irq(event, data): + if event not in ( + _IRQ_L2CAP_CONNECT, + _IRQ_L2CAP_DISCONNECT, + _IRQ_L2CAP_RECV, + _IRQ_L2CAP_SEND_READY, + ): + return + + # All the L2CAP events start with (conn_handle, cid, ...) + if connection := DeviceConnection._connected.get(data[0], None): + if channel := connection._l2cap_channel: + # Expect to match the cid for this conn handle (unless we're + # waiting for connection in which case channel._cid is None). + if channel._cid is not None and channel._cid != data[1]: + return + + # Update the channel object with new information. + if event == _IRQ_L2CAP_CONNECT: + _, channel._cid, _, channel.our_mtu, channel.peer_mtu = data + elif event == _IRQ_L2CAP_DISCONNECT: + _, _, psm, status = data + channel._status = status + channel._cid = None + connection._l2cap_channel = None + elif event == _IRQ_L2CAP_RECV: + channel._data_ready = True + elif event == _IRQ_L2CAP_SEND_READY: + channel._stalled = False + + # Notify channel. + channel._event.set() + + +def _l2cap_shutdown(): + global _listening + _listening = False + + +register_irq_handler(_l2cap_irq, _l2cap_shutdown) + + +# The channel was disconnected during a send/recvinto/flush. +class L2CAPDisconnectedError(Exception): + pass + + +# Failed to connect to connection (argument is status). +class L2CAPConnectionError(Exception): + pass + + +class L2CAPChannel: + def __init__(self, connection): + if not connection.is_connected(): + raise ValueError("Not connected") + + if connection._l2cap_channel: + raise ValueError("Already has channel") + connection._l2cap_channel = self + + self._connection = connection + + # Maximum size that the other side can send to us. + self.our_mtu = 0 + # Maximum size that we can send. + self.peer_mtu = 0 + + # Set back to None on disconnection. + self._cid = None + # Set during disconnection. + self._status = 0 + + # If true, must wait for _IRQ_L2CAP_SEND_READY IRQ before sending. + self._stalled = False + + # Has received a _IRQ_L2CAP_RECV since the buffer was last emptied. + self._data_ready = False + + self._event = asyncio.ThreadSafeFlag() + + def _assert_connected(self): + if self._cid is None: + raise L2CAPDisconnectedError + + async def recvinto(self, buf, timeout_ms=None): + self._assert_connected() + + # Wait until the data_ready flag is set. This flag is only ever set by + # the event and cleared by this function. + with self._connection.timeout(timeout_ms): + while not self._data_ready: + await self._event.wait() + self._assert_connected() + + self._assert_connected() + + # Extract up to len(buf) bytes from the channel buffer. + n = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, buf) + + # Check if there's still remaining data in the channel buffers. + self._data_ready = ble.l2cap_recvinto(self._connection._conn_handle, self._cid, None) > 0 + + return n + + # Synchronously see if there's data ready. + def available(self): + self._assert_connected() + return self._data_ready + + # Waits until the channel is free and then sends buf. + # If the buffer is larger than the MTU it will be sent in chunks. + async def send(self, buf, timeout_ms=None, chunk_size=None): + offset = 0 + chunk_size = min(self.our_mtu * 2, self.peer_mtu, chunk_size or self.peer_mtu) + mv = memoryview(buf) + while offset < len(buf): + if self._stalled: + await self.flush(timeout_ms) + # l2cap_send returns True if you can send immediately. + self._assert_connected() + self._stalled = not ble.l2cap_send( + self._connection._conn_handle, + self._cid, + mv[offset : offset + chunk_size], + ) + offset += chunk_size + + async def flush(self, timeout_ms=None): + self._assert_connected() + # Wait for the _stalled flag to be cleared by the IRQ. + with self._connection.timeout(timeout_ms): + while self._stalled: + await self._event.wait() + self._assert_connected() + + async def disconnect(self, timeout_ms=1000): + if self._cid is None: + return + + # Wait for the cid to be cleared by the disconnect IRQ. + ble.l2cap_disconnect(self._connection._conn_handle, self._cid) + await self.disconnected(timeout_ms) + + async def disconnected(self, timeout_ms=1000): + with self._connection.timeout(timeout_ms): + while self._cid is not None: + await self._event.wait() + + # Context manager -- automatically disconnect. + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_val, exc_traceback): + await self.disconnect() + + +# Use connection.l2cap_accept() instead of calling this directly. +async def accept(connection, psm, mtu, timeout_ms): + global _listening + + channel = L2CAPChannel(connection) + + # Start the stack listening if necessary. + if not _listening: + ble.l2cap_listen(psm, mtu) + _listening = True + + # Wait for the connect irq from the remote connection. + with connection.timeout(timeout_ms): + await channel._event.wait() + return channel + + +# Use connection.l2cap_connect() instead of calling this directly. +async def connect(connection, psm, mtu, timeout_ms): + if _listening: + raise ValueError("Can't connect while listening") + + channel = L2CAPChannel(connection) + + with connection.timeout(timeout_ms): + ble.l2cap_connect(connection._conn_handle, psm, mtu) + + # Wait for the connect irq from the remote connection. + # If the connection fails, we get a disconnect event (with status) instead. + await channel._event.wait() + + if channel._cid is not None: + return channel + else: + raise L2CAPConnectionError(channel._status) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/l2cap.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/l2cap.pyi new file mode 100644 index 000000000..b98177752 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/l2cap.pyi @@ -0,0 +1,40 @@ +from .core import ble as ble, log_error as log_error, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_L2CAP_ACCEPT: int +_IRQ_L2CAP_CONNECT: int +_IRQ_L2CAP_DISCONNECT: int +_IRQ_L2CAP_RECV: int +_IRQ_L2CAP_SEND_READY: int +_listening: bool + +def _l2cap_irq(event, data) -> None: ... +def _l2cap_shutdown() -> None: ... + +class L2CAPDisconnectedError(Exception): ... +class L2CAPConnectionError(Exception): ... + +class L2CAPChannel: + _connection: Incomplete + our_mtu: int + peer_mtu: int + _cid: Incomplete + _status: int + _stalled: bool + _data_ready: bool + _event: Incomplete + def __init__(self, connection) -> None: ... + def _assert_connected(self) -> None: ... + async def recvinto(self, buf, timeout_ms=None): ... + def available(self): ... + async def send(self, buf, timeout_ms=None, chunk_size=None) -> None: ... + async def flush(self, timeout_ms=None) -> None: ... + async def disconnect(self, timeout_ms: int = 1000) -> None: ... + async def disconnected(self, timeout_ms: int = 1000) -> None: ... + async def __aenter__(self): ... + async def __aexit__(self, exc_type, exc_val, exc_traceback) -> None: ... + +async def accept(connection, psm, mtu, timeout_ms): ... +async def connect(connection, psm, mtu, timeout_ms): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/peripheral.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/peripheral.py new file mode 100644 index 000000000..041678d76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/peripheral.py @@ -0,0 +1,176 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const + +import bluetooth +import struct + +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, +) +from .device import Device, DeviceConnection, DeviceTimeout + + +_IRQ_CENTRAL_CONNECT = 1 +_IRQ_CENTRAL_DISCONNECT = 2 + + +_ADV_TYPE_FLAGS = 0x01 +_ADV_TYPE_NAME = 0x09 +_ADV_TYPE_UUID16_COMPLETE = 0x3 +_ADV_TYPE_UUID32_COMPLETE = 0x5 +_ADV_TYPE_UUID128_COMPLETE = 0x7 +_ADV_TYPE_UUID16_MORE = 0x2 +_ADV_TYPE_UUID32_MORE = 0x4 +_ADV_TYPE_UUID128_MORE = 0x6 +_ADV_TYPE_APPEARANCE = 0x19 +_ADV_TYPE_MANUFACTURER = 0xFF + +_ADV_PAYLOAD_MAX_LEN = 31 + + +_incoming_connection = None +_connect_event = None + + +def _peripheral_irq(event, data): + global _incoming_connection + + if event == _IRQ_CENTRAL_CONNECT: + conn_handle, addr_type, addr = data + + # Create, initialise, and register the device. + device = Device(addr_type, bytes(addr)) + _incoming_connection = DeviceConnection(device) + _incoming_connection._conn_handle = conn_handle + DeviceConnection._connected[conn_handle] = _incoming_connection + + # Signal advertise() to return the connected device. + _connect_event.set() + + elif event == _IRQ_CENTRAL_DISCONNECT: + conn_handle, _, _ = data + if connection := DeviceConnection._connected.get(conn_handle, None): + # Tell the device_task that it should terminate. + connection._event.set() + + +def _peripheral_shutdown(): + global _incoming_connection, _connect_event + _incoming_connection = None + _connect_event = None + + +register_irq_handler(_peripheral_irq, _peripheral_shutdown) + + +# Advertising payloads are repeated packets of the following form: +# 1 byte data length (N + 1) +# 1 byte type (see constants below) +# N bytes type-specific data +def _append(adv_data, resp_data, adv_type, value): + data = struct.pack("BB", len(value) + 1, adv_type) + value + + if len(data) + len(adv_data) < _ADV_PAYLOAD_MAX_LEN: + adv_data += data + return resp_data + + if len(data) + (len(resp_data) if resp_data else 0) < _ADV_PAYLOAD_MAX_LEN: + if not resp_data: + # Overflow into resp_data for the first time. + resp_data = bytearray() + resp_data += data + return resp_data + + raise ValueError("Advertising payload too long") + + +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable=True, + limited_disc=False, + br_edr=False, + name=None, + services=None, + appearance=0, + manufacturer=None, + timeout_ms=None, +): + global _incoming_connection, _connect_event + + ensure_active() + + if not adv_data and not resp_data: + # If the user didn't manually specify adv_data / resp_data then + # construct them from the kwargs. Keep adding fields to adv_data, + # overflowing to resp_data if necessary. + # TODO: Try and do better bin-packing than just concatenating in + # order? + + adv_data = bytearray() + + resp_data = _append( + adv_data, + resp_data, + _ADV_TYPE_FLAGS, + struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), + ) + + # Services are prioritised to go in the advertising data because iOS supports + # filtering scan results by service only, so services must come first. + if services: + for uuid_len, code in ( + (2, _ADV_TYPE_UUID16_COMPLETE), + (4, _ADV_TYPE_UUID32_COMPLETE), + (16, _ADV_TYPE_UUID128_COMPLETE), + ): + if uuids := [bytes(uuid) for uuid in services if len(bytes(uuid)) == uuid_len]: + resp_data = _append(adv_data, resp_data, code, b"".join(uuids)) + + if name: + resp_data = _append(adv_data, resp_data, _ADV_TYPE_NAME, name) + + if appearance: + # See org.bluetooth.characteristic.gap.appearance.xml + resp_data = _append(adv_data, resp_data, _ADV_TYPE_APPEARANCE, struct.pack(" None: ... +def _peripheral_shutdown() -> None: ... +def _append(adv_data, resp_data, adv_type, value): ... +async def advertise( + interval_us, + adv_data=None, + resp_data=None, + connectable: bool = True, + limited_disc: bool = False, + br_edr: bool = False, + name=None, + services=None, + appearance: int = 0, + manufacturer=None, + timeout_ms=None, +): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/security.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/security.py new file mode 100644 index 000000000..3be819356 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/security.py @@ -0,0 +1,175 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const, schedule +import asyncio +import binascii +import json + +from .core import log_info, log_warn, ble, register_irq_handler +from .device import DeviceConnection + +_IRQ_ENCRYPTION_UPDATE = 28 +_IRQ_GET_SECRET = 29 +_IRQ_SET_SECRET = 30 +_IRQ_PASSKEY_ACTION = 31 + +_IO_CAPABILITY_DISPLAY_ONLY = 0 +_IO_CAPABILITY_DISPLAY_YESNO = 1 +_IO_CAPABILITY_KEYBOARD_ONLY = 2 +_IO_CAPABILITY_NO_INPUT_OUTPUT = 3 +_IO_CAPABILITY_KEYBOARD_DISPLAY = 4 + +_PASSKEY_ACTION_INPUT = 2 +_PASSKEY_ACTION_DISP = 3 +_PASSKEY_ACTION_NUMCMP = 4 + +_DEFAULT_PATH = "ble_secrets.json" + +_secrets = {} +_modified = False +_path = None + + +# Must call this before stack startup. +def load_secrets(path=None): + global _path, _secrets + + # Use path if specified, otherwise use previous path, otherwise use + # default path. + _path = path or _path or _DEFAULT_PATH + + # Reset old secrets. + _secrets = {} + try: + with open(_path, "r") as f: + entries = json.load(f) + for sec_type, key, value in entries: + # Decode bytes from hex. + _secrets[sec_type, binascii.a2b_base64(key)] = binascii.a2b_base64(value) + except: + log_warn("No secrets available") + + +# Call this whenever the secrets dict changes. +def _save_secrets(arg=None): + global _modified, _path + + _path = _path or _DEFAULT_PATH + + if not _modified: + # Only save if the secrets changed. + return + + with open(_path, "w") as f: + # Convert bytes to hex strings (otherwise JSON will treat them like + # strings). + json_secrets = [(sec_type, binascii.b2a_base64(key), binascii.b2a_base64(value)) for (sec_type, key), value in _secrets.items()] + json.dump(json_secrets, f) + _modified = False + + +def _security_irq(event, data): + global _modified + + if event == _IRQ_ENCRYPTION_UPDATE: + # Connection has updated (usually due to pairing). + conn_handle, encrypted, authenticated, bonded, key_size = data + log_info("encryption update", conn_handle, encrypted, authenticated, bonded, key_size) + if connection := DeviceConnection._connected.get(conn_handle, None): + connection.encrypted = encrypted + connection.authenticated = authenticated + connection.bonded = bonded + connection.key_size = key_size + # TODO: Handle failure. + if encrypted and connection._pair_event: + connection._pair_event.set() + + elif event == _IRQ_SET_SECRET: + sec_type, key, value = data + key = sec_type, bytes(key) + value = bytes(value) if value else None + + log_info("set secret:", key, value) + + if value is None: + # Delete secret. + if key not in _secrets: + return False + + del _secrets[key] + else: + # Save secret. + _secrets[key] = value + + # Queue up a save (don't synchronously write to flash). + _modified = True + schedule(_save_secrets, None) + + return True + + elif event == _IRQ_GET_SECRET: + sec_type, index, key = data + + log_info("get secret:", sec_type, index, bytes(key) if key else None) + + if key is None: + # Return the index'th secret of this type. + i = 0 + for (t, _key), value in _secrets.items(): + if t == sec_type: + if i == index: + return value + i += 1 + return None + else: + # Return the secret for this key (or None). + key = sec_type, bytes(key) + return _secrets.get(key, None) + + elif event == _IRQ_PASSKEY_ACTION: + conn_handle, action, passkey = data + log_info("passkey action", conn_handle, action, passkey) + # if action == _PASSKEY_ACTION_NUMCMP: + # # TODO: Show this passkey and confirm accept/reject. + # accept = 1 + # self._ble.gap_passkey(conn_handle, action, accept) + # elif action == _PASSKEY_ACTION_DISP: + # # TODO: Generate and display a passkey so the remote device can enter it. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # elif action == _PASSKEY_ACTION_INPUT: + # # TODO: Ask the user to enter the passkey shown on the remote device. + # passkey = 123456 + # self._ble.gap_passkey(conn_handle, action, passkey) + # else: + # log_warn("unknown passkey action") + + +def _security_shutdown(): + global _secrets, _modified, _path + _secrets = {} + _modified = False + _path = None + + +register_irq_handler(_security_irq, _security_shutdown) + + +# Use device.pair() rather than calling this directly. +async def pair( + connection, + bond=True, + le_secure=True, + mitm=False, + io=_IO_CAPABILITY_NO_INPUT_OUTPUT, + timeout_ms=20000, +): + ble.config(bond=bond, le_secure=le_secure, mitm=mitm, io=io) + + with connection.timeout(timeout_ms): + connection._pair_event = asyncio.ThreadSafeFlag() + ble.gap_pair(connection._conn_handle) + await connection._pair_event.wait() + # TODO: Allow the passkey action to return to here and + # invoke a callback or task to process the action. diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/security.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/security.pyi new file mode 100644 index 000000000..63f4a7582 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/security.pyi @@ -0,0 +1,27 @@ +from .core import ble as ble, log_info as log_info, log_warn as log_warn, register_irq_handler as register_irq_handler +from .device import DeviceConnection as DeviceConnection +from _typeshed import Incomplete +from micropython import const as const + +_IRQ_ENCRYPTION_UPDATE: int +_IRQ_GET_SECRET: int +_IRQ_SET_SECRET: int +_IRQ_PASSKEY_ACTION: int +_IO_CAPABILITY_DISPLAY_ONLY: int +_IO_CAPABILITY_DISPLAY_YESNO: int +_IO_CAPABILITY_KEYBOARD_ONLY: int +_IO_CAPABILITY_NO_INPUT_OUTPUT: int +_IO_CAPABILITY_KEYBOARD_DISPLAY: int +_PASSKEY_ACTION_INPUT: int +_PASSKEY_ACTION_DISP: int +_PASSKEY_ACTION_NUMCMP: int +_DEFAULT_PATH: str +_secrets: Incomplete +_modified: bool +_path: Incomplete + +def load_secrets(path=None) -> None: ... +def _save_secrets(arg=None) -> None: ... +def _security_irq(event, data): ... +def _security_shutdown() -> None: ... +async def pair(connection, bond: bool = True, le_secure: bool = True, mitm: bool = False, io=..., timeout_ms: int = 20000) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/server.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/server.py new file mode 100644 index 000000000..e8b7497f1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/server.py @@ -0,0 +1,336 @@ +# MicroPython aioble module +# MIT license; Copyright (c) 2021 Jim Mussared + +from micropython import const +from collections import deque +import bluetooth +import asyncio + +from .core import ( + ensure_active, + ble, + log_info, + log_error, + log_warn, + register_irq_handler, + GattError, +) +from .device import DeviceConnection, DeviceTimeout + +_registered_characteristics = {} + +_IRQ_GATTS_WRITE = 3 +_IRQ_GATTS_READ_REQUEST = 4 +_IRQ_GATTS_INDICATE_DONE = 20 + +_FLAG_READ = 0x0002 +_FLAG_WRITE_NO_RESPONSE = 0x0004 +_FLAG_WRITE = 0x0008 +_FLAG_NOTIFY = 0x0010 +_FLAG_INDICATE = 0x0020 + +_FLAG_READ_ENCRYPTED = 0x0200 +_FLAG_READ_AUTHENTICATED = 0x0400 +_FLAG_READ_AUTHORIZED = 0x0800 +_FLAG_WRITE_ENCRYPTED = 0x1000 +_FLAG_WRITE_AUTHENTICATED = 0x2000 +_FLAG_WRITE_AUTHORIZED = 0x4000 + +_FLAG_WRITE_CAPTURE = 0x10000 + + +_WRITE_CAPTURE_QUEUE_LIMIT = 10 + + +def _server_irq(event, data): + if event == _IRQ_GATTS_WRITE: + conn_handle, attr_handle = data + Characteristic._remote_write(conn_handle, attr_handle) + elif event == _IRQ_GATTS_READ_REQUEST: + conn_handle, attr_handle = data + return Characteristic._remote_read(conn_handle, attr_handle) + elif event == _IRQ_GATTS_INDICATE_DONE: + conn_handle, value_handle, status = data + Characteristic._indicate_done(conn_handle, value_handle, status) + + +def _server_shutdown(): + global _registered_characteristics + _registered_characteristics = {} + if hasattr(BaseCharacteristic, "_capture_task"): + BaseCharacteristic._capture_task.cancel() + del BaseCharacteristic._capture_queue + del BaseCharacteristic._capture_write_event + del BaseCharacteristic._capture_consumed_event + del BaseCharacteristic._capture_task + + +register_irq_handler(_server_irq, _server_shutdown) + + +class Service: + def __init__(self, uuid): + self.uuid = uuid + self.characteristics = [] + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, tuple(c._tuple() for c in self.characteristics)) + + +class BaseCharacteristic: + def _register(self, value_handle): + self._value_handle = value_handle + _registered_characteristics[value_handle] = self + if self._initial is not None: + self.write(self._initial) + self._initial = None + + # Read value from local db. + def read(self): + if self._value_handle is None: + return self._initial or b"" + else: + return ble.gatts_read(self._value_handle) + + # Write value to local db, and optionally notify/indicate subscribers. + def write(self, data, send_update=False): + if self._value_handle is None: + self._initial = data + else: + ble.gatts_write(self._value_handle, data, send_update) + + # When the a capture-enabled characteristic is created, create the + # necessary events (if not already created). + @staticmethod + def _init_capture(): + if hasattr(BaseCharacteristic, "_capture_queue"): + return + + BaseCharacteristic._capture_queue = deque((), _WRITE_CAPTURE_QUEUE_LIMIT) + BaseCharacteristic._capture_write_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_consumed_event = asyncio.ThreadSafeFlag() + BaseCharacteristic._capture_task = asyncio.create_task(BaseCharacteristic._run_capture_task()) + + # Monitor the shared queue for incoming characteristic writes and forward + # them sequentially to the individual characteristic events. + @staticmethod + async def _run_capture_task(): + write = BaseCharacteristic._capture_write_event + consumed = BaseCharacteristic._capture_consumed_event + q = BaseCharacteristic._capture_queue + + while True: + if len(q): + conn, data, characteristic = q.popleft() + # Let the characteristic waiting in `written()` know that it + # can proceed. + characteristic._write_data = (conn, data) + characteristic._write_event.set() + # Wait for the characteristic to complete `written()` before + # continuing. + await consumed.wait() + + if not len(q): + await write.wait() + + # Wait for a write on this characteristic. Returns the connection that did + # the write, or a tuple of (connection, value) if capture is enabled for + # this characteristics. + async def written(self, timeout_ms=None): + if not hasattr(self, "_write_event"): + # Not a writable characteristic. + return + + # If no write has been seen then we need to wait. If the event has + # already been set this will clear the event and continue + # immediately. In regular mode, this is set by the write IRQ + # directly (in _remote_write). In capture mode, this is set when it's + # our turn by _capture_task. + with DeviceTimeout(None, timeout_ms): + await self._write_event.wait() + + # Return the write data and clear the stored copy. + # In default usage this will be just the connection handle. + # In capture mode this will be a tuple of (connection_handle, received_data) + data = self._write_data + self._write_data = None + + if self.flags & _FLAG_WRITE_CAPTURE: + # Notify the shared queue monitor that the event has been consumed + # by the caller to `written()` and another characteristic can now + # proceed. + BaseCharacteristic._capture_consumed_event.set() + + return data + + def on_read(self, connection): + return 0 + + def _remote_write(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + # If we've gone from empty to one item, then wake something + # blocking on `await char.written()`. + + conn = DeviceConnection._connected.get(conn_handle, None) + + if characteristic.flags & _FLAG_WRITE_CAPTURE: + # For capture, we append the connection and the written value + # value to the shared queue along with the matching characteristic object. + # The deque will enforce the max queue len. + data = characteristic.read() + BaseCharacteristic._capture_queue.append((conn, data, characteristic)) + BaseCharacteristic._capture_write_event.set() + else: + # Store the write connection handle to be later used to retrieve the data + # then set event to handle in written() task. + characteristic._write_data = conn + characteristic._write_event.set() + + def _remote_read(conn_handle, value_handle): + if characteristic := _registered_characteristics.get(value_handle, None): + return characteristic.on_read(DeviceConnection._connected.get(conn_handle, None)) + + +class Characteristic(BaseCharacteristic): + def __init__( + self, + service, + uuid, + read=False, + write=False, + write_no_response=False, + notify=False, + indicate=False, + initial=None, + capture=False, + ): + service.characteristics.append(self) + self.descriptors = [] + + flags = 0 + if read: + flags |= _FLAG_READ + if write or write_no_response: + flags |= (_FLAG_WRITE if write else 0) | (_FLAG_WRITE_NO_RESPONSE if write_no_response else 0) + if capture: + # Capture means that we keep track of all writes, and capture + # their values (and connection) in a queue. Otherwise we just + # track the connection of the most recent write. + flags |= _FLAG_WRITE_CAPTURE + BaseCharacteristic._init_capture() + + # Set when this characteristic has a value waiting in self._write_data. + self._write_event = asyncio.ThreadSafeFlag() + # The connection of the most recent write, or a tuple of + # (connection, data) if capture is enabled. + self._write_data = None + if notify: + flags |= _FLAG_NOTIFY + if indicate: + flags |= _FLAG_INDICATE + # TODO: This should probably be a dict of connection to (ev, status). + # Right now we just support a single indication at a time. + self._indicate_connection = None + self._indicate_event = asyncio.ThreadSafeFlag() + self._indicate_status = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + if self.descriptors: + return (self.uuid, self.flags, tuple(d._tuple() for d in self.descriptors)) + else: + # Workaround: v1.19 and below can't handle an empty descriptor tuple. + return (self.uuid, self.flags) + + def notify(self, connection, data=None): + if not (self.flags & _FLAG_NOTIFY): + raise ValueError("Not supported") + ble.gatts_notify(connection._conn_handle, self._value_handle, data) + + async def indicate(self, connection, data=None, timeout_ms=1000): + if not (self.flags & _FLAG_INDICATE): + raise ValueError("Not supported") + if self._indicate_connection is not None: + raise ValueError("In progress") + if not connection.is_connected(): + raise ValueError("Not connected") + + self._indicate_connection = connection + self._indicate_status = None + + try: + with connection.timeout(timeout_ms): + ble.gatts_indicate(connection._conn_handle, self._value_handle, data) + await self._indicate_event.wait() + if self._indicate_status != 0: + raise GattError(self._indicate_status) + finally: + self._indicate_connection = None + + def _indicate_done(conn_handle, value_handle, status): + if characteristic := _registered_characteristics.get(value_handle, None): + if connection := DeviceConnection._connected.get(conn_handle, None): + if not characteristic._indicate_connection: + # Timeout. + return + # See TODO in __init__ to support multiple concurrent indications. + assert connection == characteristic._indicate_connection + characteristic._indicate_status = status + characteristic._indicate_event.set() + + +class BufferedCharacteristic(Characteristic): + def __init__(self, *args, max_len=20, append=False, **kwargs): + super().__init__(*args, **kwargs) + self._max_len = max_len + self._append = append + + def _register(self, value_handle): + super()._register(value_handle) + ble.gatts_set_buffer(value_handle, self._max_len, self._append) + + +class Descriptor(BaseCharacteristic): + def __init__(self, characteristic, uuid, read=False, write=False, initial=None): + characteristic.descriptors.append(self) + + flags = 0 + if read: + flags |= _FLAG_READ + if write: + flags |= _FLAG_WRITE + self._write_event = asyncio.ThreadSafeFlag() + self._write_data = None + + self.uuid = uuid + self.flags = flags + self._value_handle = None + self._initial = initial + + # Generate tuple for gatts_register_services. + def _tuple(self): + return (self.uuid, self.flags) + + +# Turn the Service/Characteristic/Descriptor classes into a registration tuple +# and then extract their value handles. +def register_services(*services): + ensure_active() + _registered_characteristics.clear() + handles = ble.gatts_register_services(tuple(s._tuple() for s in services)) + for i in range(len(services)): + service_handles = handles[i] + service = services[i] + n = 0 + for characteristic in service.characteristics: + characteristic._register(service_handles[n]) + n += 1 + for descriptor in characteristic.descriptors: + descriptor._register(service_handles[n]) + n += 1 diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/server.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/server.pyi new file mode 100644 index 000000000..a03184b1a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/aioble/server.pyi @@ -0,0 +1,101 @@ +from .core import ( + GattError as GattError, + ble as ble, + ensure_active as ensure_active, + log_error as log_error, + log_info as log_info, + log_warn as log_warn, + register_irq_handler as register_irq_handler, +) +from .device import DeviceConnection as DeviceConnection, DeviceTimeout as DeviceTimeout +from _typeshed import Incomplete +from micropython import const as const + +_registered_characteristics: Incomplete +_IRQ_GATTS_WRITE: int +_IRQ_GATTS_READ_REQUEST: int +_IRQ_GATTS_INDICATE_DONE: int +_FLAG_READ: int +_FLAG_WRITE_NO_RESPONSE: int +_FLAG_WRITE: int +_FLAG_NOTIFY: int +_FLAG_INDICATE: int +_FLAG_READ_ENCRYPTED: int +_FLAG_READ_AUTHENTICATED: int +_FLAG_READ_AUTHORIZED: int +_FLAG_WRITE_ENCRYPTED: int +_FLAG_WRITE_AUTHENTICATED: int +_FLAG_WRITE_AUTHORIZED: int +_FLAG_WRITE_CAPTURE: int +_WRITE_CAPTURE_QUEUE_LIMIT: int + +def _server_irq(event, data): ... +def _server_shutdown() -> None: ... + +class Service: + uuid: Incomplete + characteristics: Incomplete + def __init__(self, uuid) -> None: ... + def _tuple(self): ... + +class BaseCharacteristic: + _value_handle: Incomplete + _initial: Incomplete + def _register(self, value_handle) -> None: ... + def read(self): ... + def write(self, data, send_update: bool = False) -> None: ... + @staticmethod + def _init_capture() -> None: ... + @staticmethod + async def _run_capture_task() -> None: ... + _write_data: Incomplete + async def written(self, timeout_ms=None): ... + def on_read(self, connection): ... + def _remote_write(conn_handle, value_handle) -> None: ... + def _remote_read(conn_handle, value_handle): ... + +class Characteristic(BaseCharacteristic): + descriptors: Incomplete + _write_event: Incomplete + _write_data: Incomplete + _indicate_connection: Incomplete + _indicate_event: Incomplete + _indicate_status: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__( + self, + service, + uuid, + read: bool = False, + write: bool = False, + write_no_response: bool = False, + notify: bool = False, + indicate: bool = False, + initial=None, + capture: bool = False, + ) -> None: ... + def _tuple(self): ... + def notify(self, connection, data=None) -> None: ... + async def indicate(self, connection, data=None, timeout_ms: int = 1000) -> None: ... + def _indicate_done(conn_handle, value_handle, status) -> None: ... + +class BufferedCharacteristic(Characteristic): + _max_len: Incomplete + _append: Incomplete + def __init__(self, *args, max_len: int = 20, append: bool = False, **kwargs) -> None: ... + def _register(self, value_handle) -> None: ... + +class Descriptor(BaseCharacteristic): + _write_event: Incomplete + _write_data: Incomplete + uuid: Incomplete + flags: Incomplete + _value_handle: Incomplete + _initial: Incomplete + def __init__(self, characteristic, uuid, read: bool = False, write: bool = False, initial=None) -> None: ... + def _tuple(self): ... + +def register_services(*services) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/modules.json new file mode 100644 index 000000000..87308a96b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/modules.json @@ -0,0 +1,92 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "OPENMV_N6", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "aioble/__init__.py", + "module": "__init__" + }, + { + "file": "aioble/central.py", + "module": "central" + }, + { + "file": "aioble/client.py", + "module": "client" + }, + { + "file": "aioble/core.py", + "module": "core" + }, + { + "file": "aioble/device.py", + "module": "device" + }, + { + "file": "aioble/l2cap.py", + "module": "l2cap" + }, + { + "file": "aioble/peripheral.py", + "module": "peripheral" + }, + { + "file": "aioble/security.py", + "module": "security" + }, + { + "file": "aioble/server.py", + "module": "server" + }, + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/OPENMV_N6/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/lcd160cr.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/lcd160cr.py new file mode 100644 index 000000000..4fb6c99ed --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/lcd160cr.py @@ -0,0 +1,479 @@ +# Driver for official MicroPython LCD160CR display +# MIT license; Copyright (c) 2017 Damien P. George + +from micropython import const +import machine +from utime import sleep_ms +from ustruct import calcsize, pack_into +import errno + +# for set_orient +PORTRAIT = 0 +LANDSCAPE = 1 +PORTRAIT_UPSIDEDOWN = 2 +LANDSCAPE_UPSIDEDOWN = 3 + +# for set_startup_deco; can be or'd +STARTUP_DECO_NONE = 0 +STARTUP_DECO_MLOGO = 1 +STARTUP_DECO_INFO = 2 + +_uart_baud_table = { + 2400: 0, + 4800: 1, + 9600: 2, + 19200: 3, + 38400: 4, + 57600: 5, + 115200: 6, + 230400: 7, + 460800: 8, +} + + +class LCD160CR: + def __init__(self, connect=None, *, pwr=None, i2c=None, spi=None, i2c_addr=98): + if connect in ("X", "Y", "XY", "YX"): + i = connect[-1] + j = connect[0] + y = j + "4" + elif connect == "C": + i = 2 + j = 2 + y = "A7" + else: + if pwr is None or i2c is None or spi is None: + raise ValueError('must specify valid "connect" or all of "pwr", "i2c" and "spi"') + + if pwr is None: + pwr = machine.Pin(y, machine.Pin.OUT) + if i2c is None: + i2c = machine.I2C(i, freq=1000000) + if spi is None: + spi = machine.SPI(j, baudrate=13500000, polarity=0, phase=0) + + if not pwr.value(): + pwr(1) + sleep_ms(10) + # else: + # alread have power + # lets be optimistic... + + # set connections + self.pwr = pwr + self.i2c = i2c + self.spi = spi + self.i2c_addr = i2c_addr + + # create temp buffers and memoryviews + self.buf16 = bytearray(16) + self.buf19 = bytearray(19) + self.buf = [None] * 10 + for i in range(1, 10): + self.buf[i] = memoryview(self.buf16)[0:i] + self.buf1 = self.buf[1] + self.array4 = [0, 0, 0, 0] + + # set default orientation and window + self.set_orient(PORTRAIT) + self._fcmd2b("= n: + self.i2c.readfrom_into(self.i2c_addr, buf) + return + t -= 1 + sleep_ms(1) + raise OSError(errno.ETIMEDOUT) + + def oflush(self, n=255): + t = 5000 + while t: + self.i2c.readfrom_into(self.i2c_addr + 1, self.buf1) + r = self.buf1[0] + if r >= n: + return + t -= 1 + machine.idle() + raise OSError(errno.ETIMEDOUT) + + def iflush(self): + t = 5000 + while t: + self.i2c.readfrom_into(self.i2c_addr, self.buf16) + if self.buf16[0] == 0: + return + t -= 1 + sleep_ms(1) + raise OSError(errno.ETIMEDOUT) + + #### MISC METHODS #### + + @staticmethod + def rgb(r, g, b): + return ((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3) + + @staticmethod + def clip_line(c, w, h): + while True: + ca = ce = 0 + if c[1] < 0: + ca |= 8 + elif c[1] > h: + ca |= 4 + if c[0] < 0: + ca |= 1 + elif c[0] > w: + ca |= 2 + if c[3] < 0: + ce |= 8 + elif c[3] > h: + ce |= 4 + if c[2] < 0: + ce |= 1 + elif c[2] > w: + ce |= 2 + if ca & ce: + return False + elif ca | ce: + ca |= ce + if ca & 1: + if c[2] < c[0]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[1] += ((-c[0]) * (c[3] - c[1])) // (c[2] - c[0]) + c[0] = 0 + elif ca & 2: + if c[2] < c[0]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[3] += ((w - 1 - c[2]) * (c[3] - c[1])) // (c[2] - c[0]) + c[2] = w - 1 + elif ca & 4: + if c[0] == c[2]: + if c[1] >= h: + c[1] = h - 1 + if c[3] >= h: + c[3] = h - 1 + else: + if c[3] < c[1]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[2] += ((h - 1 - c[3]) * (c[2] - c[0])) // (c[3] - c[1]) + c[3] = h - 1 + else: + if c[0] == c[2]: + c[1] = max(c[1], 0) + c[3] = max(c[3], 0) + else: + if c[3] < c[1]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[0] += ((-c[1]) * (c[2] - c[0])) // (c[3] - c[1]) + c[1] = 0 + else: + return True + + #### SETUP COMMANDS #### + + def set_power(self, on): + self.pwr(on) + sleep_ms(15) + + def set_orient(self, orient): + self._fcmd2("= 2: + self.i2c.readfrom_into(self.i2c_addr, self.buf[3]) + return self.buf[3][1] | self.buf[3][2] << 8 + t -= 1 + sleep_ms(1) + raise OSError(errno.ETIMEDOUT) + + def get_line(self, x, y, buf): + l = len(buf) // 2 + self._fcmd2b("= l: + self.i2c.readfrom_into(self.i2c_addr, buf) + return + t -= 1 + sleep_ms(1) + raise OSError(errno.ETIMEDOUT) + + def screen_dump(self, buf, x=0, y=0, w=None, h=None): + if w is None: + w = self.w - x + if h is None: + h = self.h - y + if w <= 127: + line = bytearray(2 * w + 1) + line2 = None + else: + # split line if more than 254 bytes needed + buflen = (w + 1) // 2 + line = bytearray(2 * buflen + 1) + line2 = memoryview(line)[: 2 * (w - buflen) + 1] + for i in range(min(len(buf) // (2 * w), h)): + ix = i * w * 2 + self.get_line(x, y + i, line) + buf[ix : ix + len(line) - 1] = memoryview(line)[1:] + ix += len(line) - 1 + if line2: + self.get_line(x + buflen, y + i, line2) + buf[ix : ix + len(line2) - 1] = memoryview(line2)[1:] + ix += len(line2) - 1 + + def screen_load(self, buf): + l = self.w * self.h * 2 + 2 + self._fcmd2b("= 0x200: + self._send(ar[n : n + 0x200]) + n += 0x200 + else: + self._send(ar[n:]) + while n < self.w * self.h * 2: + self._send(b"\x00") + n += 1 + + #### TEXT COMMANDS #### + + def set_pos(self, x, y): + self._fcmd2("= self.w or y >= self.h: + return + elif x < 0 or y < 0: + left = top = True + if x < 0: + left = False + w += x + x = 0 + if y < 0: + top = False + h += y + y = 0 + if cmd == 0x51 or cmd == 0x72: + # draw interior + self._fcmd2b("> 7 != 0 + + def get_touch(self): + self._send(b"\x02T") # implicit LCD output flush + b = self.buf[4] + self._waitfor(3, b) + return b[1] >> 7, b[2], b[3] + + #### ADVANCED COMMANDS #### + + def set_spi_win(self, x, y, w, h): + pack_into(" 32: + raise ValueError("length must be 32 or less") + self._fcmd2(" 0xFFFF: + raise ValueError("length must be 65535 or less") + self.oflush() + self._fcmd2("`_ + for how the display can be connected to the pyboard. + """ + + @overload + def __init__(self, *, pwr: Pin, i2c: I2C, spi: SPI, i2c_addr: int = 98): + """ + Construct an LCD160CR object. The parameters are: + + - *connect* is a string specifying the physical connection of the LCD + display to the board; valid values are "X", "Y", "XY", "YX". + Use "X" when the display is connected to a pyboard in the X-skin + position, and "Y" when connected in the Y-skin position. "XY" + and "YX" are used when the display is connected to the right or + left side of the pyboard, respectively. + - *pwr* is a Pin object connected to the LCD's power/enabled pin. + - *i2c* is an I2C object connected to the LCD's I2C interface. + - *spi* is an SPI object connected to the LCD's SPI interface. + - *i2c_addr* is the I2C address of the display. + + One must specify either a valid *connect* or all of *pwr*, *i2c* and *spi*. + If a valid *connect* is given then any of *pwr*, *i2c* or *spi* which are + not passed as parameters (i.e. they are ``None``) will be created based on the + value of *connect*. This allows to override the default interface to the + display if needed. + + The default values are: + + - "X" is for the X-skin and uses: + ``pwr=Pin("X4")``, ``i2c=I2C("X")``, ``spi=SPI("X")`` + - "Y" is for the Y-skin and uses: + ``pwr=Pin("Y4")``, ``i2c=I2C("Y")``, ``spi=SPI("Y")`` + - "XY" is for the right-side and uses: + ``pwr=Pin("X4")``, ``i2c=I2C("Y")``, ``spi=SPI("X")`` + - "YX" is for the left-side and uses: + ``pwr=Pin("Y4")``, ``i2c=I2C("X")``, ``spi=SPI("Y")`` + + See `this image `_ + for how the display can be connected to the pyboard. + """ + def _send(self, cmd) -> None: ... + def _fcmd2(self, fmt, a0, a1: int = 0, a2: int = 0) -> None: ... + def _fcmd2b(self, fmt, a0, a1, a2, a3, a4: int = 0) -> None: ... + def _waitfor(self, n, buf) -> None: ... + def oflush(self, n: int = 255) -> None: ... + def iflush(self) -> None: ... + @staticmethod + def rgb(r, g, b) -> int: + """ + Return a 16-bit integer representing the given rgb color values. The + 16-bit value can be used to set the font color (see + :meth:`LCD160CR.set_text_color`) pen color (see :meth:`LCD160CR.set_pen`) + and draw individual pixels. + """ + ... + @staticmethod + def clip_line(c, w, h) -> int: + """ + Clip the given line data. This is for internal use. + """ + ... + def set_power(self, on) -> None: + """ + Turn the display on or off, depending on the given value of *on*: 0 or ``False`` + will turn the display off, and 1 or ``True`` will turn it on. + """ + ... + w: Incomplete + h: Incomplete + """\ + The width and height of the display, respectively, in pixels. These + members are updated when calling :meth:`LCD160CR.set_orient` and should + be considered read-only. + """ + def set_orient(self, orient) -> None: + """ + Set the orientation of the display. The *orient* parameter can be one + of `PORTRAIT`, `LANDSCAPE`, `PORTRAIT_UPSIDEDOWN`, `LANDSCAPE_UPSIDEDOWN`. + """ + ... + def set_brightness(self, value) -> None: + """ + Set the brightness of the display, between 0 and 31. + """ + ... + def set_i2c_addr(self, addr) -> None: + """ + Set the I2C address of the display. The *addr* value must have the + lower 2 bits cleared. + """ + ... + def set_uart_baudrate(self, baudrate) -> None: + """ + Set the baudrate of the UART interface. + """ + ... + def set_startup_deco(self, value) -> None: + """ + Set the start-up decoration of the display. The *value* parameter can be a + logical or of `STARTUP_DECO_NONE`, `STARTUP_DECO_MLOGO`, `STARTUP_DECO_INFO`. + """ + ... + def save_to_flash(self) -> None: + """ + Save the following parameters to flash so they persist on restart and power up: + initial decoration, orientation, brightness, UART baud rate, I2C address. + """ + ... + def set_pixel(self, x, y, c) -> None: + """ + Set the specified pixel to the given color. The color should be a 16-bit + integer and can be created by :meth:`LCD160CR.rgb`. + """ + ... + def get_pixel(self, x, y) -> int: + """ + Get the 16-bit value of the specified pixel. + """ + ... + def get_line(self, x, y, buf) -> None: + """ + Low-level method to get a line of pixels into the given buffer. + To read *n* pixels *buf* should be *2*n+1* bytes in length. The first byte + is a dummy byte and should be ignored, and subsequent bytes represent the + pixels in the line starting at coordinate *(x, y)*. + """ + ... + def screen_dump(self, buf, x: int = 0, y: int = 0, w=None, h=None) -> None: + """ + Dump the contents of the screen to the given buffer. The parameters *x* and *y* + specify the starting coordinate, and *w* and *h* the size of the region. If *w* + or *h* are ``None`` then they will take on their maximum values, set by the size + of the screen minus the given *x* and *y* values. *buf* should be large enough + to hold ``2*w*h`` bytes. If it's smaller then only the initial horizontal lines + will be stored. + """ + ... + def screen_load(self, buf) -> None: + """ + Load the entire screen from the given buffer. + """ + ... + def set_pos(self, x, y) -> None: + """ + Set the position for text output using :meth:`LCD160CR.write`. The position + is the upper-left corner of the text. + """ + ... + def set_text_color(self, fg, bg) -> None: + """ + Set the foreground and background color of the text. + """ + ... + def set_font(self, font, scale: int = 0, bold: int = 0, trans: int = 0, scroll: int = 0) -> None: + """ + Set the font for the text. Subsequent calls to `write` will use the newly + configured font. The parameters are: + + - *font* is the font family to use, valid values are 0, 1, 2, 3. + - *scale* is a scaling value for each character pixel, where the pixels + are drawn as a square with side length equal to *scale + 1*. The value + can be between 0 and 63. + - *bold* controls the number of pixels to overdraw each character pixel, + making a bold effect. The lower 2 bits of *bold* are the number of + pixels to overdraw in the horizontal direction, and the next 2 bits are + for the vertical direction. For example, a *bold* value of 5 will + overdraw 1 pixel in both the horizontal and vertical directions. + - *trans* can be either 0 or 1 and if set to 1 the characters will be + drawn with a transparent background. + - *scroll* can be either 0 or 1 and if set to 1 the display will do a + soft scroll if the text moves to the next line. + """ + ... + def write(self, s) -> None: + """ + Write text to the display, using the current position, color and font. + As text is written the position is automatically incremented. The + display supports basic VT100 control codes such as newline and backspace. + """ + ... + def set_pen(self, line, fill) -> None: + """ + Set the line and fill color for primitive shapes. + """ + ... + def erase(self) -> None: + """ + Erase the entire display to the pen fill color. + """ + ... + def dot(self, x, y) -> None: + """ + Draw a single pixel at the given location using the pen line color. + """ + ... + def rect(self, x, y, w, h, cmd: int = 114) -> None: + """ + Draw a rectangle at the given location and size using the pen line + color for the outline, and the pen fill color for the interior. + The `rect` method draws the outline and interior, while the other methods + just draw one or the other. + """ + ... + def rect_outline(self, x, y, w, h) -> None: + """ + Draw a rectangle at the given location and size using the pen line + color for the outline, and the pen fill color for the interior. + The `rect` method draws the outline and interior, while the other methods + just draw one or the other. + """ + ... + def rect_interior(self, x, y, w, h) -> None: + """ + Draw a rectangle at the given location and size using the pen line + color for the outline, and the pen fill color for the interior. + The `rect` method draws the outline and interior, while the other methods + just draw one or the other. + """ + ... + def line(self, x1, y1, x2, y2) -> None: + """ + Draw a line between the given coordinates using the pen line color. + """ + ... + def dot_no_clip(self, x, y) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def rect_no_clip(self, x, y, w, h) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def rect_outline_no_clip(self, x, y, w, h) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def rect_interior_no_clip(self, x, y, w, h) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def line_no_clip(self, x1, y1, x2, y2) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def poly_dot(self, data) -> None: + """ + Draw a sequence of dots using the pen line color. + The *data* should be a buffer of bytes, with each successive pair of + bytes corresponding to coordinate pairs (x, y). + """ + ... + def poly_line(self, data) -> None: + """ + Similar to :meth:`LCD160CR.poly_dot` but draws lines between the dots. + """ + ... + def touch_config(self, calib: bool = False, save: bool = False, irq=None) -> None: + """ + Configure the touch panel: + + - If *calib* is ``True`` then the call will trigger a touch calibration of + the resistive touch sensor. This requires the user to touch various + parts of the screen. + - If *save* is ``True`` then the touch parameters will be saved to NVRAM + to persist across reset/power up. + - If *irq* is ``True`` then the display will be configured to pull the IRQ + line low when a touch force is detected. If *irq* is ``False`` then this + feature is disabled. If *irq* is ``None`` (the default value) then no + change is made to this setting. + """ + ... + def is_touched(self) -> bool: + """ + Returns a boolean: ``True`` if there is currently a touch force on the screen, + ``False`` otherwise. + """ + ... + def get_touch(self) -> Tuple: + """ + Returns a 3-tuple of: *(active, x, y)*. If there is currently a touch force + on the screen then *active* is 1, otherwise it is 0. The *x* and *y* values + indicate the position of the current or most recent touch. + """ + ... + def set_spi_win(self, x, y, w, h) -> None: + """ + Set the window that SPI data is written to. + """ + ... + def fast_spi(self, flush: bool = True) -> SPI: + """ + Ready the display to accept RGB pixel data on the SPI bus, resetting the location + of the first byte to go to the top-left corner of the window set by + :meth:`LCD160CR.set_spi_win`. + The method returns an SPI object which can be used to write the pixel data. + + Pixels should be sent as 16-bit RGB values in the 5-6-5 format. The destination + counter will increase as data is sent, and data can be sent in arbitrary sized + chunks. Once the destination counter reaches the end of the window specified by + :meth:`LCD160CR.set_spi_win` it will wrap around to the top-left corner of that window. + """ + ... + def show_framebuf(self, buf) -> None: + """ + Show the given buffer on the display. *buf* should be an array of bytes containing + the 16-bit RGB values for the pixels, and they will be written to the area + specified by :meth:`LCD160CR.set_spi_win`, starting from the top-left corner. + + The `framebuf `_ module can be used to construct frame buffers + and provides drawing primitives. Using a frame buffer will improve + performance of animations when compared to drawing directly to the screen. + """ + ... + def set_scroll(self, on) -> None: + """ + Turn scrolling on or off. This controls globally whether any window regions will + scroll. + """ + ... + def set_scroll_win( + self, win, x: int = -1, y: int = 0, w: int = 0, h: int = 0, vec: int = 0, pat: int = 0, fill: int = 2016, color: int = 0 + ) -> None: + """ + Configure a window region for scrolling: + + - *win* is the window id to configure. There are 0..7 standard windows for + general purpose use. Window 8 is the text scroll window (the ticker). + - *x*, *y*, *w*, *h* specify the location of the window in the display. + - *vec* specifies the direction and speed of scroll: it is a 16-bit value + of the form ``0bF.ddSSSSSSSSSSSS``. *dd* is 0, 1, 2, 3 for +x, +y, -x, + -y scrolling. *F* sets the speed format, with 0 meaning that the window + is shifted *S % 256* pixel every frame, and 1 meaning that the window + is shifted 1 pixel every *S* frames. + - *pat* is a 16-bit pattern mask for the background. + - *fill* is the fill color. + - *color* is the extra color, either of the text or pattern foreground. + """ + ... + def set_scroll_win_param(self, win, param, value) -> None: + """ + Set a single parameter of a scrolling window region: + + - *win* is the window id, 0..8. + - *param* is the parameter number to configure, 0..7, and corresponds + to the parameters in the `set_scroll_win` method. + - *value* is the value to set. + """ + ... + def set_scroll_buf(self, s) -> None: + """ + Set the string for scrolling in window 8. The parameter *s* must be a string + with length 32 or less. + """ + ... + def jpeg_start(self, l) -> None: + """ + Display a JPEG with the data split across multiple buffers. There must be + a single call to `jpeg_start` to begin with, specifying the total number of + bytes in the JPEG. Then this number of bytes must be transferred to the + display using one or more calls to the `jpeg_data` command. + """ + ... + def jpeg_data(self, buf) -> None: + """ + Display a JPEG with the data split across multiple buffers. There must be + a single call to `jpeg_start` to begin with, specifying the total number of + bytes in the JPEG. Then this number of bytes must be transferred to the + display using one or more calls to the `jpeg_data` command. + """ + ... + def jpeg(self, buf) -> None: + """ + Display a JPEG. *buf* should contain the entire JPEG data. JPEG data should + not include EXIF information. The following encodings are supported: Baseline + DCT, Huffman coding, 8 bits per sample, 3 color components, YCbCr4:2:2. + The origin of the JPEG is set by :meth:`LCD160CR.set_pos`. + """ + ... + def feed_wdt(self) -> None: + """ + The first call to this method will start the display's internal watchdog + timer. Subsequent calls will feed the watchdog. The timeout is roughly 30 + seconds. + """ + ... + def reset(self) -> None: + """ + Reset the display. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/modules.json new file mode 100644 index 000000000..dcfce1784 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/modules.json @@ -0,0 +1,60 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "PYBD_SF2", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "lcd160cr.py", + "module": "lcd160cr" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBD_SF2/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/lcd160cr.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/lcd160cr.py new file mode 100644 index 000000000..4fb6c99ed --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/lcd160cr.py @@ -0,0 +1,479 @@ +# Driver for official MicroPython LCD160CR display +# MIT license; Copyright (c) 2017 Damien P. George + +from micropython import const +import machine +from utime import sleep_ms +from ustruct import calcsize, pack_into +import errno + +# for set_orient +PORTRAIT = 0 +LANDSCAPE = 1 +PORTRAIT_UPSIDEDOWN = 2 +LANDSCAPE_UPSIDEDOWN = 3 + +# for set_startup_deco; can be or'd +STARTUP_DECO_NONE = 0 +STARTUP_DECO_MLOGO = 1 +STARTUP_DECO_INFO = 2 + +_uart_baud_table = { + 2400: 0, + 4800: 1, + 9600: 2, + 19200: 3, + 38400: 4, + 57600: 5, + 115200: 6, + 230400: 7, + 460800: 8, +} + + +class LCD160CR: + def __init__(self, connect=None, *, pwr=None, i2c=None, spi=None, i2c_addr=98): + if connect in ("X", "Y", "XY", "YX"): + i = connect[-1] + j = connect[0] + y = j + "4" + elif connect == "C": + i = 2 + j = 2 + y = "A7" + else: + if pwr is None or i2c is None or spi is None: + raise ValueError('must specify valid "connect" or all of "pwr", "i2c" and "spi"') + + if pwr is None: + pwr = machine.Pin(y, machine.Pin.OUT) + if i2c is None: + i2c = machine.I2C(i, freq=1000000) + if spi is None: + spi = machine.SPI(j, baudrate=13500000, polarity=0, phase=0) + + if not pwr.value(): + pwr(1) + sleep_ms(10) + # else: + # alread have power + # lets be optimistic... + + # set connections + self.pwr = pwr + self.i2c = i2c + self.spi = spi + self.i2c_addr = i2c_addr + + # create temp buffers and memoryviews + self.buf16 = bytearray(16) + self.buf19 = bytearray(19) + self.buf = [None] * 10 + for i in range(1, 10): + self.buf[i] = memoryview(self.buf16)[0:i] + self.buf1 = self.buf[1] + self.array4 = [0, 0, 0, 0] + + # set default orientation and window + self.set_orient(PORTRAIT) + self._fcmd2b("= n: + self.i2c.readfrom_into(self.i2c_addr, buf) + return + t -= 1 + sleep_ms(1) + raise OSError(errno.ETIMEDOUT) + + def oflush(self, n=255): + t = 5000 + while t: + self.i2c.readfrom_into(self.i2c_addr + 1, self.buf1) + r = self.buf1[0] + if r >= n: + return + t -= 1 + machine.idle() + raise OSError(errno.ETIMEDOUT) + + def iflush(self): + t = 5000 + while t: + self.i2c.readfrom_into(self.i2c_addr, self.buf16) + if self.buf16[0] == 0: + return + t -= 1 + sleep_ms(1) + raise OSError(errno.ETIMEDOUT) + + #### MISC METHODS #### + + @staticmethod + def rgb(r, g, b): + return ((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3) + + @staticmethod + def clip_line(c, w, h): + while True: + ca = ce = 0 + if c[1] < 0: + ca |= 8 + elif c[1] > h: + ca |= 4 + if c[0] < 0: + ca |= 1 + elif c[0] > w: + ca |= 2 + if c[3] < 0: + ce |= 8 + elif c[3] > h: + ce |= 4 + if c[2] < 0: + ce |= 1 + elif c[2] > w: + ce |= 2 + if ca & ce: + return False + elif ca | ce: + ca |= ce + if ca & 1: + if c[2] < c[0]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[1] += ((-c[0]) * (c[3] - c[1])) // (c[2] - c[0]) + c[0] = 0 + elif ca & 2: + if c[2] < c[0]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[3] += ((w - 1 - c[2]) * (c[3] - c[1])) // (c[2] - c[0]) + c[2] = w - 1 + elif ca & 4: + if c[0] == c[2]: + if c[1] >= h: + c[1] = h - 1 + if c[3] >= h: + c[3] = h - 1 + else: + if c[3] < c[1]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[2] += ((h - 1 - c[3]) * (c[2] - c[0])) // (c[3] - c[1]) + c[3] = h - 1 + else: + if c[0] == c[2]: + c[1] = max(c[1], 0) + c[3] = max(c[3], 0) + else: + if c[3] < c[1]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[0] += ((-c[1]) * (c[2] - c[0])) // (c[3] - c[1]) + c[1] = 0 + else: + return True + + #### SETUP COMMANDS #### + + def set_power(self, on): + self.pwr(on) + sleep_ms(15) + + def set_orient(self, orient): + self._fcmd2("= 2: + self.i2c.readfrom_into(self.i2c_addr, self.buf[3]) + return self.buf[3][1] | self.buf[3][2] << 8 + t -= 1 + sleep_ms(1) + raise OSError(errno.ETIMEDOUT) + + def get_line(self, x, y, buf): + l = len(buf) // 2 + self._fcmd2b("= l: + self.i2c.readfrom_into(self.i2c_addr, buf) + return + t -= 1 + sleep_ms(1) + raise OSError(errno.ETIMEDOUT) + + def screen_dump(self, buf, x=0, y=0, w=None, h=None): + if w is None: + w = self.w - x + if h is None: + h = self.h - y + if w <= 127: + line = bytearray(2 * w + 1) + line2 = None + else: + # split line if more than 254 bytes needed + buflen = (w + 1) // 2 + line = bytearray(2 * buflen + 1) + line2 = memoryview(line)[: 2 * (w - buflen) + 1] + for i in range(min(len(buf) // (2 * w), h)): + ix = i * w * 2 + self.get_line(x, y + i, line) + buf[ix : ix + len(line) - 1] = memoryview(line)[1:] + ix += len(line) - 1 + if line2: + self.get_line(x + buflen, y + i, line2) + buf[ix : ix + len(line2) - 1] = memoryview(line2)[1:] + ix += len(line2) - 1 + + def screen_load(self, buf): + l = self.w * self.h * 2 + 2 + self._fcmd2b("= 0x200: + self._send(ar[n : n + 0x200]) + n += 0x200 + else: + self._send(ar[n:]) + while n < self.w * self.h * 2: + self._send(b"\x00") + n += 1 + + #### TEXT COMMANDS #### + + def set_pos(self, x, y): + self._fcmd2("= self.w or y >= self.h: + return + elif x < 0 or y < 0: + left = top = True + if x < 0: + left = False + w += x + x = 0 + if y < 0: + top = False + h += y + y = 0 + if cmd == 0x51 or cmd == 0x72: + # draw interior + self._fcmd2b("> 7 != 0 + + def get_touch(self): + self._send(b"\x02T") # implicit LCD output flush + b = self.buf[4] + self._waitfor(3, b) + return b[1] >> 7, b[2], b[3] + + #### ADVANCED COMMANDS #### + + def set_spi_win(self, x, y, w, h): + pack_into(" 32: + raise ValueError("length must be 32 or less") + self._fcmd2(" 0xFFFF: + raise ValueError("length must be 65535 or less") + self.oflush() + self._fcmd2("`_ + for how the display can be connected to the pyboard. + """ + + @overload + def __init__(self, *, pwr: Pin, i2c: I2C, spi: SPI, i2c_addr: int = 98): + """ + Construct an LCD160CR object. The parameters are: + + - *connect* is a string specifying the physical connection of the LCD + display to the board; valid values are "X", "Y", "XY", "YX". + Use "X" when the display is connected to a pyboard in the X-skin + position, and "Y" when connected in the Y-skin position. "XY" + and "YX" are used when the display is connected to the right or + left side of the pyboard, respectively. + - *pwr* is a Pin object connected to the LCD's power/enabled pin. + - *i2c* is an I2C object connected to the LCD's I2C interface. + - *spi* is an SPI object connected to the LCD's SPI interface. + - *i2c_addr* is the I2C address of the display. + + One must specify either a valid *connect* or all of *pwr*, *i2c* and *spi*. + If a valid *connect* is given then any of *pwr*, *i2c* or *spi* which are + not passed as parameters (i.e. they are ``None``) will be created based on the + value of *connect*. This allows to override the default interface to the + display if needed. + + The default values are: + + - "X" is for the X-skin and uses: + ``pwr=Pin("X4")``, ``i2c=I2C("X")``, ``spi=SPI("X")`` + - "Y" is for the Y-skin and uses: + ``pwr=Pin("Y4")``, ``i2c=I2C("Y")``, ``spi=SPI("Y")`` + - "XY" is for the right-side and uses: + ``pwr=Pin("X4")``, ``i2c=I2C("Y")``, ``spi=SPI("X")`` + - "YX" is for the left-side and uses: + ``pwr=Pin("Y4")``, ``i2c=I2C("X")``, ``spi=SPI("Y")`` + + See `this image `_ + for how the display can be connected to the pyboard. + """ + def _send(self, cmd) -> None: ... + def _fcmd2(self, fmt, a0, a1: int = 0, a2: int = 0) -> None: ... + def _fcmd2b(self, fmt, a0, a1, a2, a3, a4: int = 0) -> None: ... + def _waitfor(self, n, buf) -> None: ... + def oflush(self, n: int = 255) -> None: ... + def iflush(self) -> None: ... + @staticmethod + def rgb(r, g, b) -> int: + """ + Return a 16-bit integer representing the given rgb color values. The + 16-bit value can be used to set the font color (see + :meth:`LCD160CR.set_text_color`) pen color (see :meth:`LCD160CR.set_pen`) + and draw individual pixels. + """ + ... + @staticmethod + def clip_line(c, w, h) -> int: + """ + Clip the given line data. This is for internal use. + """ + ... + def set_power(self, on) -> None: + """ + Turn the display on or off, depending on the given value of *on*: 0 or ``False`` + will turn the display off, and 1 or ``True`` will turn it on. + """ + ... + w: Incomplete + h: Incomplete + """\ + The width and height of the display, respectively, in pixels. These + members are updated when calling :meth:`LCD160CR.set_orient` and should + be considered read-only. + """ + def set_orient(self, orient) -> None: + """ + Set the orientation of the display. The *orient* parameter can be one + of `PORTRAIT`, `LANDSCAPE`, `PORTRAIT_UPSIDEDOWN`, `LANDSCAPE_UPSIDEDOWN`. + """ + ... + def set_brightness(self, value) -> None: + """ + Set the brightness of the display, between 0 and 31. + """ + ... + def set_i2c_addr(self, addr) -> None: + """ + Set the I2C address of the display. The *addr* value must have the + lower 2 bits cleared. + """ + ... + def set_uart_baudrate(self, baudrate) -> None: + """ + Set the baudrate of the UART interface. + """ + ... + def set_startup_deco(self, value) -> None: + """ + Set the start-up decoration of the display. The *value* parameter can be a + logical or of `STARTUP_DECO_NONE`, `STARTUP_DECO_MLOGO`, `STARTUP_DECO_INFO`. + """ + ... + def save_to_flash(self) -> None: + """ + Save the following parameters to flash so they persist on restart and power up: + initial decoration, orientation, brightness, UART baud rate, I2C address. + """ + ... + def set_pixel(self, x, y, c) -> None: + """ + Set the specified pixel to the given color. The color should be a 16-bit + integer and can be created by :meth:`LCD160CR.rgb`. + """ + ... + def get_pixel(self, x, y) -> int: + """ + Get the 16-bit value of the specified pixel. + """ + ... + def get_line(self, x, y, buf) -> None: + """ + Low-level method to get a line of pixels into the given buffer. + To read *n* pixels *buf* should be *2*n+1* bytes in length. The first byte + is a dummy byte and should be ignored, and subsequent bytes represent the + pixels in the line starting at coordinate *(x, y)*. + """ + ... + def screen_dump(self, buf, x: int = 0, y: int = 0, w=None, h=None) -> None: + """ + Dump the contents of the screen to the given buffer. The parameters *x* and *y* + specify the starting coordinate, and *w* and *h* the size of the region. If *w* + or *h* are ``None`` then they will take on their maximum values, set by the size + of the screen minus the given *x* and *y* values. *buf* should be large enough + to hold ``2*w*h`` bytes. If it's smaller then only the initial horizontal lines + will be stored. + """ + ... + def screen_load(self, buf) -> None: + """ + Load the entire screen from the given buffer. + """ + ... + def set_pos(self, x, y) -> None: + """ + Set the position for text output using :meth:`LCD160CR.write`. The position + is the upper-left corner of the text. + """ + ... + def set_text_color(self, fg, bg) -> None: + """ + Set the foreground and background color of the text. + """ + ... + def set_font(self, font, scale: int = 0, bold: int = 0, trans: int = 0, scroll: int = 0) -> None: + """ + Set the font for the text. Subsequent calls to `write` will use the newly + configured font. The parameters are: + + - *font* is the font family to use, valid values are 0, 1, 2, 3. + - *scale* is a scaling value for each character pixel, where the pixels + are drawn as a square with side length equal to *scale + 1*. The value + can be between 0 and 63. + - *bold* controls the number of pixels to overdraw each character pixel, + making a bold effect. The lower 2 bits of *bold* are the number of + pixels to overdraw in the horizontal direction, and the next 2 bits are + for the vertical direction. For example, a *bold* value of 5 will + overdraw 1 pixel in both the horizontal and vertical directions. + - *trans* can be either 0 or 1 and if set to 1 the characters will be + drawn with a transparent background. + - *scroll* can be either 0 or 1 and if set to 1 the display will do a + soft scroll if the text moves to the next line. + """ + ... + def write(self, s) -> None: + """ + Write text to the display, using the current position, color and font. + As text is written the position is automatically incremented. The + display supports basic VT100 control codes such as newline and backspace. + """ + ... + def set_pen(self, line, fill) -> None: + """ + Set the line and fill color for primitive shapes. + """ + ... + def erase(self) -> None: + """ + Erase the entire display to the pen fill color. + """ + ... + def dot(self, x, y) -> None: + """ + Draw a single pixel at the given location using the pen line color. + """ + ... + def rect(self, x, y, w, h, cmd: int = 114) -> None: + """ + Draw a rectangle at the given location and size using the pen line + color for the outline, and the pen fill color for the interior. + The `rect` method draws the outline and interior, while the other methods + just draw one or the other. + """ + ... + def rect_outline(self, x, y, w, h) -> None: + """ + Draw a rectangle at the given location and size using the pen line + color for the outline, and the pen fill color for the interior. + The `rect` method draws the outline and interior, while the other methods + just draw one or the other. + """ + ... + def rect_interior(self, x, y, w, h) -> None: + """ + Draw a rectangle at the given location and size using the pen line + color for the outline, and the pen fill color for the interior. + The `rect` method draws the outline and interior, while the other methods + just draw one or the other. + """ + ... + def line(self, x1, y1, x2, y2) -> None: + """ + Draw a line between the given coordinates using the pen line color. + """ + ... + def dot_no_clip(self, x, y) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def rect_no_clip(self, x, y, w, h) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def rect_outline_no_clip(self, x, y, w, h) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def rect_interior_no_clip(self, x, y, w, h) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def line_no_clip(self, x1, y1, x2, y2) -> None: + """ + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + """ + ... + def poly_dot(self, data) -> None: + """ + Draw a sequence of dots using the pen line color. + The *data* should be a buffer of bytes, with each successive pair of + bytes corresponding to coordinate pairs (x, y). + """ + ... + def poly_line(self, data) -> None: + """ + Similar to :meth:`LCD160CR.poly_dot` but draws lines between the dots. + """ + ... + def touch_config(self, calib: bool = False, save: bool = False, irq=None) -> None: + """ + Configure the touch panel: + + - If *calib* is ``True`` then the call will trigger a touch calibration of + the resistive touch sensor. This requires the user to touch various + parts of the screen. + - If *save* is ``True`` then the touch parameters will be saved to NVRAM + to persist across reset/power up. + - If *irq* is ``True`` then the display will be configured to pull the IRQ + line low when a touch force is detected. If *irq* is ``False`` then this + feature is disabled. If *irq* is ``None`` (the default value) then no + change is made to this setting. + """ + ... + def is_touched(self) -> bool: + """ + Returns a boolean: ``True`` if there is currently a touch force on the screen, + ``False`` otherwise. + """ + ... + def get_touch(self) -> Tuple: + """ + Returns a 3-tuple of: *(active, x, y)*. If there is currently a touch force + on the screen then *active* is 1, otherwise it is 0. The *x* and *y* values + indicate the position of the current or most recent touch. + """ + ... + def set_spi_win(self, x, y, w, h) -> None: + """ + Set the window that SPI data is written to. + """ + ... + def fast_spi(self, flush: bool = True) -> SPI: + """ + Ready the display to accept RGB pixel data on the SPI bus, resetting the location + of the first byte to go to the top-left corner of the window set by + :meth:`LCD160CR.set_spi_win`. + The method returns an SPI object which can be used to write the pixel data. + + Pixels should be sent as 16-bit RGB values in the 5-6-5 format. The destination + counter will increase as data is sent, and data can be sent in arbitrary sized + chunks. Once the destination counter reaches the end of the window specified by + :meth:`LCD160CR.set_spi_win` it will wrap around to the top-left corner of that window. + """ + ... + def show_framebuf(self, buf) -> None: + """ + Show the given buffer on the display. *buf* should be an array of bytes containing + the 16-bit RGB values for the pixels, and they will be written to the area + specified by :meth:`LCD160CR.set_spi_win`, starting from the top-left corner. + + The `framebuf `_ module can be used to construct frame buffers + and provides drawing primitives. Using a frame buffer will improve + performance of animations when compared to drawing directly to the screen. + """ + ... + def set_scroll(self, on) -> None: + """ + Turn scrolling on or off. This controls globally whether any window regions will + scroll. + """ + ... + def set_scroll_win( + self, win, x: int = -1, y: int = 0, w: int = 0, h: int = 0, vec: int = 0, pat: int = 0, fill: int = 2016, color: int = 0 + ) -> None: + """ + Configure a window region for scrolling: + + - *win* is the window id to configure. There are 0..7 standard windows for + general purpose use. Window 8 is the text scroll window (the ticker). + - *x*, *y*, *w*, *h* specify the location of the window in the display. + - *vec* specifies the direction and speed of scroll: it is a 16-bit value + of the form ``0bF.ddSSSSSSSSSSSS``. *dd* is 0, 1, 2, 3 for +x, +y, -x, + -y scrolling. *F* sets the speed format, with 0 meaning that the window + is shifted *S % 256* pixel every frame, and 1 meaning that the window + is shifted 1 pixel every *S* frames. + - *pat* is a 16-bit pattern mask for the background. + - *fill* is the fill color. + - *color* is the extra color, either of the text or pattern foreground. + """ + ... + def set_scroll_win_param(self, win, param, value) -> None: + """ + Set a single parameter of a scrolling window region: + + - *win* is the window id, 0..8. + - *param* is the parameter number to configure, 0..7, and corresponds + to the parameters in the `set_scroll_win` method. + - *value* is the value to set. + """ + ... + def set_scroll_buf(self, s) -> None: + """ + Set the string for scrolling in window 8. The parameter *s* must be a string + with length 32 or less. + """ + ... + def jpeg_start(self, l) -> None: + """ + Display a JPEG with the data split across multiple buffers. There must be + a single call to `jpeg_start` to begin with, specifying the total number of + bytes in the JPEG. Then this number of bytes must be transferred to the + display using one or more calls to the `jpeg_data` command. + """ + ... + def jpeg_data(self, buf) -> None: + """ + Display a JPEG with the data split across multiple buffers. There must be + a single call to `jpeg_start` to begin with, specifying the total number of + bytes in the JPEG. Then this number of bytes must be transferred to the + display using one or more calls to the `jpeg_data` command. + """ + ... + def jpeg(self, buf) -> None: + """ + Display a JPEG. *buf* should contain the entire JPEG data. JPEG data should + not include EXIF information. The following encodings are supported: Baseline + DCT, Huffman coding, 8 bits per sample, 3 color components, YCbCr4:2:2. + The origin of the JPEG is set by :meth:`LCD160CR.set_pos`. + """ + ... + def feed_wdt(self) -> None: + """ + The first call to this method will start the display's internal watchdog + timer. Subsequent calls will feed the watchdog. The timeout is roughly 30 + seconds. + """ + ... + def reset(self) -> None: + """ + Reset the display. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/modules.json new file mode 100644 index 000000000..9ab502ba2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/modules.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "PYBV10", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "lcd160cr.py", + "module": "lcd160cr" + }, + { + "file": "onewire.py", + "module": "onewire" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/PYBV10/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/modules.json new file mode 100644 index 000000000..3c61bd68e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "STM32F769DISC", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F769DISC/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/modules.json new file mode 100644 index 000000000..58e14213d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "STM32F7DISC", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32F7DISC/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/modules.json new file mode 100644 index 000000000..da5df79b2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "STM32H573I_DK", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/STM32H573I_DK/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/dht.py b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/dht.py new file mode 100644 index 000000000..4624ae2ad --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/dht.py @@ -0,0 +1,47 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import sys +import machine + +if hasattr(machine, "dht_readinto"): + from machine import dht_readinto +elif sys.platform.startswith("esp"): + from esp import dht_readinto +elif sys.platform == "pyboard": + from pyb import dht_readinto +else: + dht_readinto = __import__(sys.platform).dht_readinto + +del machine + + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF != buf[4]: + raise Exception("checksum error") + + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7F) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/dht.pyi b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/modules.json b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/modules.json new file mode 100644 index 000000000..73dd6b947 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/modules.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "stm32", + "platform": "stm32", + "machine": "VCC_GND_F407ZG", + "firmware": "micropython-stm32-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "dht.py", + "module": "dht" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "ntptime.py", + "module": "ntptime" + }, + { + "file": "onewire.py", + "module": "onewire" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + }, + { + "file": "urequests.py", + "module": "urequests" + }, + { + "file": "webrepl.py", + "module": "webrepl" + }, + { + "file": "webrepl_setup.py", + "module": "webrepl_setup" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ntptime.py b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ntptime.py new file mode 100644 index 000000000..d77214d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ntptime.py @@ -0,0 +1,68 @@ +from time import gmtime +import socket +import struct + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" +# The NTP socket timeout can be configured at runtime by doing: ntptime.timeout = 2 +timeout = 1 + + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.settimeout(timeout) + s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + finally: + s.close() + val = struct.unpack("!I", msg[40:44])[0] + + # 2024-01-01 00:00:00 converted to an NTP timestamp + MIN_NTP_TIMESTAMP = 3913056000 + + # Y2036 fix + # + # The NTP timestamp has a 32-bit count of seconds, which will wrap back + # to zero on 7 Feb 2036 at 06:28:16. + # + # We know that this software was written during 2024 (or later). + # So we know that timestamps less than MIN_NTP_TIMESTAMP are impossible. + # So if the timestamp is less than MIN_NTP_TIMESTAMP, that probably means + # that the NTP time wrapped at 2^32 seconds. (Or someone set the wrong + # time on their NTP server, but we can't really do anything about that). + # + # So in that case, we need to add in those extra 2^32 seconds, to get the + # correct timestamp. + # + # This means that this code will work until the year 2160. More precisely, + # this code will not work after 7th Feb 2160 at 06:28:15. + # + if val < MIN_NTP_TIMESTAMP: + val += 0x100000000 + + # Convert timestamp from NTP format to our internal format + + EPOCH_YEAR = gmtime(0)[0] + if EPOCH_YEAR == 2000: + # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 3155673600 + elif EPOCH_YEAR == 1970: + # (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 + NTP_DELTA = 2208988800 + else: + raise Exception("Unsupported epoch: {}".format(EPOCH_YEAR)) + + return val - NTP_DELTA + + +# There's currently no timezone support in MicroPython, and the RTC is set in UTC time. +def settime(): + t = time() + import machine + + tm = gmtime(t) + machine.RTC().datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ntptime.pyi b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/onewire.py b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/onewire.py new file mode 100644 index 000000000..4c6da741c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/onewire.py @@ -0,0 +1,92 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +import _onewire as _ow + + +class OneWireError(Exception): + pass + + +class OneWire: + SEARCH_ROM = 0xF0 + MATCH_ROM = 0x55 + SKIP_ROM = 0xCC + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(self.MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xFF): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(self.SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/onewire.pyi b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/removed.txt b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ssl.py b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ssl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/urequests.py b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/urequests.py new file mode 100644 index 000000000..227a1ae5c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/urequests.py @@ -0,0 +1,8 @@ +# This module provides a backwards-compatble import for `urequests`. +# It lazy-loads from `requests` without duplicating its globals dict. + + +def __getattr__(attr): + import requests + + return getattr(requests, attr) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/urequests.pyi b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl.py b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl.py new file mode 100644 index 000000000..84897696f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl.py @@ -0,0 +1,178 @@ +# This module should be imported from REPL, not run from command line. +import binascii +import hashlib +from micropython import const +import network +import os +import socket +import sys +import websocket +import _webrepl + +listen_s = None +client_s = None + +DEBUG = 0 + +_DEFAULT_STATIC_HOST = "https://micropython.org/webrepl/" +static_host = _DEFAULT_STATIC_HOST + + +def server_handshake(cl): + req = cl.makefile("rwb", 0) + # Skip HTTP GET line. + l = req.readline() + if DEBUG: + sys.stdout.write(repr(l)) + + webkey = None + upgrade = False + websocket = False + + while True: + l = req.readline() + if not l: + # EOF in headers. + return False + if l == b"\r\n": + break + if DEBUG: + sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b"Sec-WebSocket-Key": + webkey = v + elif h == b"Connection" and b"Upgrade" in v: + upgrade = True + elif h == b"Upgrade" and v == b"websocket": + websocket = True + + if not (upgrade and websocket and webkey): + return False + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + cl.send( + b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """ + ) + cl.send(respkey) + cl.send("\r\n\r\n") + + return True + + +def send_html(cl): + cl.send( + b"""\ +HTTP/1.0 200 OK\r +\r +\r +\r +""" + ) + cl.close() + + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.WLAN.IF_AP, network.WLAN.IF_STA): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL server started on http://%s:%d/" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + + if not server_handshake(cl): + send_html(cl) + return False + + prev = os.dupterm(None) + os.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return False + print("\nWebREPL connection from:", remote_addr) + client_s = cl + + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data (ESP32/ESP8266-only) + if hasattr(os, "dupterm_notify"): + cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify) + os.dupterm(ws) + + return True + + +def stop(): + global listen_s, client_s + os.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None, accept_handler=accept_conn): + global static_host + stop() + webrepl_pass = password + if webrepl_pass is None: + try: + import webrepl_cfg + + webrepl_pass = webrepl_cfg.PASS + if hasattr(webrepl_cfg, "BASE"): + static_host = webrepl_cfg.BASE + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + + _webrepl.password(webrepl_pass) + s = setup_conn(port, accept_handler) + + if accept_handler is None: + print("Starting webrepl in foreground mode") + # Run accept_conn to serve HTML until we get a websocket connection. + while not accept_conn(s): + pass + elif password is None: + print("Started webrepl in normal mode") + else: + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266, password=None): + start(port, password, None) diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl.pyi b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl_setup.py b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl_setup.py new file mode 100644 index 000000000..41b78758f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl_setup.py @@ -0,0 +1,105 @@ +import sys + +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + + +def getpass(prompt): + return input(prompt) + + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + + +main() diff --git a/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl_setup.pyi b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/stm32/VCC_GND_F407ZG/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/argparse.py b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/argparse.py new file mode 100644 index 000000000..5c92887f9 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/argparse.py @@ -0,0 +1,226 @@ +""" +Minimal and functional version of CPython's argparse module. +""" + +import sys +from collections import namedtuple + + +class _ArgError(BaseException): + pass + + +class _Arg: + def __init__(self, names, dest, action, nargs, const, default, help): + self.names = names + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.default = default + self.help = help + + def parse(self, optname, args): + # parse args for this arg + if self.action == "store": + if self.nargs is None: + if args: + return args.pop(0) + else: + raise _ArgError("expecting value for %s" % optname) + elif self.nargs == "?": + if args: + return args.pop(0) + else: + return self.default + else: + if self.nargs == "*": + n = -1 + elif self.nargs == "+": + if not args: + raise _ArgError("expecting value for %s" % optname) + n = -1 + else: + n = int(self.nargs) + ret = [] + stop_at_opt = True + while args and n != 0: + if stop_at_opt and args[0].startswith("-") and args[0] != "-": + if args[0] == "--": + stop_at_opt = False + args.pop(0) + else: + break + else: + ret.append(args.pop(0)) + n -= 1 + if n > 0: + raise _ArgError("expecting value for %s" % optname) + return ret + elif self.action == "store_const": + return self.const + else: + assert False + + +def _dest_from_optnames(opt_names): + dest = opt_names[0] + for name in opt_names: + if name.startswith("--"): + dest = name + break + return dest.lstrip("-").replace("-", "_") + + +class ArgumentParser: + def __init__(self, *, description=""): + self.description = description + self.opt = [] + self.pos = [] + + def add_argument(self, *args, **kwargs): + action = kwargs.get("action", "store") + if action == "store_true": + action = "store_const" + const = True + default = kwargs.get("default", False) + elif action == "store_false": + action = "store_const" + const = False + default = kwargs.get("default", True) + else: + const = kwargs.get("const", None) + default = kwargs.get("default", None) + if args and args[0].startswith("-"): + list = self.opt + dest = kwargs.get("dest") + if dest is None: + dest = _dest_from_optnames(args) + else: + list = self.pos + dest = kwargs.get("dest") + if dest is None: + dest = args[0] + if not args: + args = [dest] + list.append( + _Arg( + args, + dest, + action, + kwargs.get("nargs", None), + const, + default, + kwargs.get("help", ""), + ) + ) + + def usage(self, full): + # print short usage + print("usage: %s [-h]" % sys.argv[0], end="") + + def render_arg(arg): + if arg.action == "store": + if arg.nargs is None: + return " %s" % arg.dest + if isinstance(arg.nargs, int): + return " %s(x%d)" % (arg.dest, arg.nargs) + else: + return " %s%s" % (arg.dest, arg.nargs) + else: + return "" + + for opt in self.opt: + print(" [%s%s]" % (", ".join(opt.names), render_arg(opt)), end="") + for pos in self.pos: + print(render_arg(pos), end="") + print() + + if not full: + return + + # print full information + print() + if self.description: + print(self.description) + if self.pos: + print("\npositional args:") + for pos in self.pos: + print(" %-16s%s" % (pos.names[0], pos.help)) + print("\noptional args:") + print(" -h, --help show this message and exit") + for opt in self.opt: + print(" %-16s%s" % (", ".join(opt.names) + render_arg(opt), opt.help)) + + def parse_args(self, args=None): + return self._parse_args_impl(args, False) + + def parse_known_args(self, args=None): + return self._parse_args_impl(args, True) + + def _parse_args_impl(self, args, return_unknown): + if args is None: + args = sys.argv[1:] + else: + args = args[:] + try: + return self._parse_args(args, return_unknown) + except _ArgError as e: + self.usage(False) + print("error:", e) + sys.exit(2) + + def _parse_args(self, args, return_unknown): + # add optional args with defaults + arg_dest = [] + arg_vals = [] + for opt in self.opt: + arg_dest.append(opt.dest) + arg_vals.append(opt.default) + + # deal with unknown arguments, if needed + unknown = [] + + def consume_unknown(): + while args and not args[0].startswith("-"): + unknown.append(args.pop(0)) + + # parse all args + parsed_pos = False + while args or not parsed_pos: + if args and args[0].startswith("-") and args[0] != "-" and args[0] != "--": + # optional arg + a = args.pop(0) + if a in ("-h", "--help"): + self.usage(True) + sys.exit(0) + found = False + for i, opt in enumerate(self.opt): + if a in opt.names: + arg_vals[i] = opt.parse(a, args) + found = True + break + if not found: + if return_unknown: + unknown.append(a) + consume_unknown() + else: + raise _ArgError("unknown option %s" % a) + else: + # positional arg + if parsed_pos: + if return_unknown: + unknown = unknown + args + break + else: + raise _ArgError("extra args: %s" % " ".join(args)) + for pos in self.pos: + arg_dest.append(pos.dest) + arg_vals.append(pos.parse(pos.names[0], args)) + parsed_pos = True + if return_unknown: + consume_unknown() + + # build and return named tuple with arg values + values = namedtuple("args", arg_dest)(*arg_vals) + return (values, unknown) if return_unknown else values diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/argparse.pyi b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/argparse.pyi new file mode 100644 index 000000000..30ef0d1dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/argparse.pyi @@ -0,0 +1,28 @@ +from _typeshed import Incomplete + +class _ArgError(BaseException): ... + +class _Arg: + names: Incomplete + dest: Incomplete + action: Incomplete + nargs: Incomplete + const: Incomplete + default: Incomplete + help: Incomplete + def __init__(self, names, dest, action, nargs, const, default, help) -> None: ... + def parse(self, optname, args): ... + +def _dest_from_optnames(opt_names): ... + +class ArgumentParser: + description: Incomplete + opt: Incomplete + pos: Incomplete + def __init__(self, *, description: str = "") -> None: ... + def add_argument(self, *args, **kwargs) -> None: ... + def usage(self, full): ... + def parse_args(self, args=None): ... + def parse_known_args(self, args=None): ... + def _parse_args_impl(self, args, return_unknown): ... + def _parse_args(self, args, return_unknown): ... diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__init__.py b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__init__.py new file mode 100644 index 000000000..65c830ef0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__init__.py @@ -0,0 +1,187 @@ +# MicroPython package installer +# MIT license; Copyright (c) 2022 Jim Mussared + +from micropython import const +import requests +import sys + + +_PACKAGE_INDEX = "https://micropython.org/pi/v2" +_CHUNK_SIZE = 128 + +allowed_mip_url_prefixes = ("http://", "https://", "github:", "gitlab:") + + +# This implements os.makedirs(os.dirname(path)) +def _ensure_path_exists(path): + import os + + split = path.split("/") + + # Handle paths starting with "/". + if not split[0]: + split.pop(0) + split[0] = "/" + split[0] + + prefix = "" + for i in range(len(split) - 1): + prefix += split[i] + try: + os.stat(prefix) + except: + os.mkdir(prefix) + prefix += "/" + + +# Copy from src (stream) to dest (function-taking-bytes) +def _chunk(src, dest): + buf = memoryview(bytearray(_CHUNK_SIZE)) + while True: + n = src.readinto(buf) + if n == 0: + break + dest(buf if n == _CHUNK_SIZE else buf[:n]) + + +# Check if the specified path exists and matches the hash. +def _check_exists(path, short_hash): + pass + + try: + import binascii + import hashlib + + with open(path, "rb") as f: + hs256 = hashlib.sha256() + _chunk(f, hs256.update) + existing_hash = str(binascii.hexlify(hs256.digest())[: len(short_hash)], "utf-8") + return existing_hash == short_hash + except: + return False + + +def _rewrite_url(url, branch=None): + if not branch: + branch = "HEAD" + if url.startswith("github:"): + url = url[7:].split("/") + url = ( + "https://raw.githubusercontent.com/" + + url[0] + + "/" + + url[1] + + "/" + + branch + + "/" + + "/".join(url[2:]) + ) + elif url.startswith("gitlab:"): + url = url[7:].split("/") + url = ( + "https://gitlab.com/" + + url[0] + + "/" + + url[1] + + "/-/raw/" + + branch + + "/" + + "/".join(url[2:]) + ) + return url + + +def _download_file(url, dest): + response = requests.get(url) + try: + if response.status_code != 200: + print("Error", response.status_code, "requesting", url) + return False + + print("Copying:", dest) + _ensure_path_exists(dest) + with open(dest, "wb") as f: + _chunk(response.raw, f.write) + + return True + finally: + response.close() + + +def _install_json(package_json_url, index, target, version, mpy): + response = requests.get(_rewrite_url(package_json_url, version)) + try: + if response.status_code != 200: + print("Package not found:", package_json_url) + return False + + package_json = response.json() + finally: + response.close() + for target_path, short_hash in package_json.get("hashes", ()): + fs_target_path = target + "/" + target_path + if _check_exists(fs_target_path, short_hash): + print("Exists:", fs_target_path) + else: + file_url = "{}/file/{}/{}".format(index, short_hash[:2], short_hash) + if not _download_file(file_url, fs_target_path): + print("File not found: {} {}".format(target_path, short_hash)) + return False + base_url = package_json_url.rpartition("/")[0] + for target_path, url in package_json.get("urls", ()): + fs_target_path = target + "/" + target_path + is_full_url = any(url.startswith(p) for p in allowed_mip_url_prefixes) + if base_url and not is_full_url: + url = f"{base_url}/{url}" # Relative URLs + if not _download_file(_rewrite_url(url, version), fs_target_path): + print("File not found: {} {}".format(target_path, url)) + return False + for dep, dep_version in package_json.get("deps", ()): + if not _install_package(dep, index, target, dep_version, mpy): + return False + return True + + +def _install_package(package, index, target, version, mpy): + if any(package.startswith(p) for p in allowed_mip_url_prefixes): + if package.endswith(".py") or package.endswith(".mpy"): + print("Downloading {} to {}".format(package, target)) + return _download_file( + _rewrite_url(package, version), target + "/" + package.rsplit("/")[-1] + ) + else: + if not package.endswith(".json"): + if not package.endswith("/"): + package += "/" + package += "package.json" + print("Installing {} to {}".format(package, target)) + else: + if not version: + version = "latest" + print("Installing {} ({}) from {} to {}".format(package, version, index, target)) + + mpy_version = ( + sys.implementation._mpy & 0xFF if mpy and hasattr(sys.implementation, "_mpy") else "py" + ) + + package = "{}/package/{}/{}/{}.json".format(index, mpy_version, package, version) + + return _install_json(package, index, target, version, mpy) + + +def install(package, index=None, target=None, version=None, mpy=True): + if not target: + for p in sys.path: + if not p.startswith("/rom") and p.endswith("/lib"): + target = p + break + else: + print("Unable to find lib dir in sys.path") + return + + if not index: + index = _PACKAGE_INDEX + + if _install_package(package, index.rstrip("/"), target, version, mpy): + print("Done") + else: + print("Package may be partially installed") diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__init__.pyi b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__main__.py b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__main__.py new file mode 100644 index 000000000..7732638b2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__main__.py @@ -0,0 +1,46 @@ +# MicroPython package installer command line +# MIT license; Copyright (c) 2022 Jim Mussared + +import argparse +import sys + + +def do_install(): + parser = argparse.ArgumentParser() + parser.add_argument( + "-t", + "--target", + help="Directory to start discovery", + ) + parser.add_argument( + "-i", + "--index", + help="Pattern to match test files", + ) + parser.add_argument( + "--mpy", + action="store_true", + help="download as compiled .mpy files (default)", + ) + parser.add_argument( + "--no-mpy", + action="store_true", + help="download as .py source files", + ) + parser.add_argument("package", nargs="+") + args = parser.parse_args(args=sys.argv[2:]) + + from . import install + + for package in args.package: + version = None + if "@" in package: + package, version = package.split("@") + install(package, args.index, args.target, version, not args.no_mpy) + + +if len(sys.argv) >= 2: + if sys.argv[1] == "install": + do_install() + else: + print('mip: Unknown command "{}"'.format(sys.argv[1])) diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__main__.pyi b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__main__.pyi new file mode 100644 index 000000000..e5d14f82b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/mip/__main__.pyi @@ -0,0 +1 @@ +def do_install() -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/modules.json new file mode 100644 index 000000000..b1da47f4f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/modules.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "unix", + "platform": "unix", + "machine": "GENERIC", + "firmware": "micropython-unix-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "argparse.py", + "module": "argparse" + }, + { + "file": "mip/__init__.py", + "module": "__init__" + }, + { + "file": "mip/__main__.py", + "module": "__main__" + }, + { + "file": "requests/__init__.py", + "module": "__init__" + }, + { + "file": "ssl.py", + "module": "ssl" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/requests/__init__.py b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/requests/__init__.py new file mode 100644 index 000000000..4ca7489a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/requests/__init__.py @@ -0,0 +1,221 @@ +import socket + + +class Response: + def __init__(self, f): + self.raw = f + self.encoding = "utf-8" + self._cached = None + + def close(self): + if self.raw: + self.raw.close() + self.raw = None + self._cached = None + + @property + def content(self): + if self._cached is None: + try: + self._cached = self.raw.read() + finally: + self.raw.close() + self.raw = None + return self._cached + + @property + def text(self): + return str(self.content, self.encoding) + + def json(self): + import json + + return json.loads(self.content) + + +def request( + method, + url, + data=None, + json=None, + headers=None, + stream=None, + auth=None, + timeout=None, + parse_headers=True, +): + if headers is None: + headers = {} + else: + headers = headers.copy() + + redirect = None # redirection url, None means no redirection + chunked_data = data and getattr(data, "__next__", None) and not getattr(data, "__len__", None) + + if auth is not None: + import binascii + + username, password = auth + formated = b"{}:{}".format(username, password) + formated = str(binascii.b2a_base64(formated)[:-1], "ascii") + headers["Authorization"] = "Basic {}".format(formated) + + try: + proto, dummy, host, path = url.split("/", 3) + except ValueError: + proto, dummy, host = url.split("/", 2) + path = "" + if proto == "http:": + port = 80 + elif proto == "https:": + import tls + + port = 443 + else: + raise ValueError("Unsupported protocol: " + proto) + + if ":" in host: + host, port = host.split(":", 1) + port = int(port) + + ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + ai = ai[0] + + resp_d = None + if parse_headers is not False: + resp_d = {} + + s = socket.socket(ai[0], socket.SOCK_STREAM, ai[2]) + + if timeout is not None: + # Note: settimeout is not supported on all platforms, will raise + # an AttributeError if not available. + s.settimeout(timeout) + + try: + s.connect(ai[-1]) + if proto == "https:": + context = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + context.verify_mode = tls.CERT_NONE + s = context.wrap_socket(s, server_hostname=host) + s.write(b"%s /%s HTTP/1.0\r\n" % (method, path)) + + if "Host" not in headers: + headers["Host"] = host + + if json is not None: + assert data is None + from json import dumps + + data = dumps(json) + + if "Content-Type" not in headers: + headers["Content-Type"] = "application/json" + + if data: + if chunked_data: + if "Transfer-Encoding" not in headers and "Content-Length" not in headers: + headers["Transfer-Encoding"] = "chunked" + elif "Content-Length" not in headers: + headers["Content-Length"] = str(len(data)) + + if "Connection" not in headers: + headers["Connection"] = "close" + + # Iterate over keys to avoid tuple alloc + for k in headers: + s.write(k) + s.write(b": ") + s.write(headers[k]) + s.write(b"\r\n") + + s.write(b"\r\n") + + if data: + if chunked_data: + if headers.get("Transfer-Encoding", None) == "chunked": + for chunk in data: + s.write(b"%x\r\n" % len(chunk)) + s.write(chunk) + s.write(b"\r\n") + s.write("0\r\n\r\n") + else: + for chunk in data: + s.write(chunk) + else: + s.write(data) + + l = s.readline() + # print(l) + l = l.split(None, 2) + if len(l) < 2: + # Invalid response + raise ValueError("HTTP error: BadStatusLine:\n%s" % l) + status = int(l[1]) + reason = "" + if len(l) > 2: + reason = l[2].rstrip() + while True: + l = s.readline() + if not l or l == b"\r\n": + break + # print(l) + if l.startswith(b"Transfer-Encoding:"): + if b"chunked" in l: + raise ValueError("Unsupported " + str(l, "utf-8")) + elif l.startswith(b"Location:") and not 200 <= status <= 299: + if status in [301, 302, 303, 307, 308]: + redirect = str(l[10:-2], "utf-8") + else: + raise NotImplementedError("Redirect %d not yet supported" % status) + if parse_headers is False: + pass + elif parse_headers is True: + l = str(l, "utf-8") + k, v = l.split(":", 1) + resp_d[k] = v.strip() + else: + parse_headers(l, resp_d) + except OSError: + s.close() + raise + + if redirect: + s.close() + # Use the host specified in the redirect URL, as it may not be the same as the original URL. + headers.pop("Host", None) + if status in [301, 302, 303]: + return request("GET", redirect, None, None, headers, stream) + else: + return request(method, redirect, data, json, headers, stream) + else: + resp = Response(s) + resp.status_code = status + resp.reason = reason + if resp_d is not None: + resp.headers = resp_d + return resp + + +def head(url, **kw): + return request("HEAD", url, **kw) + + +def get(url, **kw): + return request("GET", url, **kw) + + +def post(url, **kw): + return request("POST", url, **kw) + + +def put(url, **kw): + return request("PUT", url, **kw) + + +def patch(url, **kw): + return request("PATCH", url, **kw) + + +def delete(url, **kw): + return request("DELETE", url, **kw) diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/requests/__init__.pyi b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/ssl.py b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/unix/GENERIC/ssl.pyi b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/unix/GENERIC/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/abc.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/abc.py new file mode 100644 index 000000000..c2c707f62 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/abc.py @@ -0,0 +1,6 @@ +class ABC: + pass + + +def abstractmethod(f): + return f diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/abc.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/abc.pyi new file mode 100644 index 000000000..34d6ee25d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/abc.pyi @@ -0,0 +1,3 @@ +class ABC: ... + +def abstractmethod(f): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/base64.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/base64.py new file mode 100644 index 000000000..d6baca05f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/base64.py @@ -0,0 +1,480 @@ +#! /usr/bin/env python3 + +"""RFC 3548: Base16, Base32, Base64 Data Encodings""" + +# Modified 04-Oct-1995 by Jack Jansen to use binascii module +# Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support +# Modified 22-May-2007 by Guido van Rossum to use bytes everywhere + +import re +import struct +import binascii + + +__all__ = [ + # Legacy interface exports traditional RFC 1521 Base64 encodings + "encode", + "decode", + "encodebytes", + "decodebytes", + # Generalized interface for other encodings + "b64encode", + "b64decode", + "b32encode", + "b32decode", + "b16encode", + "b16decode", + # Standard Base64 encoding + "standard_b64encode", + "standard_b64decode", + # Some common Base64 alternatives. As referenced by RFC 3458, see thread + # starting at: + # + # http://zgp.org/pipermail/p2p-hackers/2001-September/000316.html + "urlsafe_b64encode", + "urlsafe_b64decode", +] + + +bytes_types = (bytes, bytearray) # Types acceptable as binary data + + +def _bytes_from_decode_data(s): + if isinstance(s, str): + try: + return s.encode("ascii") + # except UnicodeEncodeError: + except: + raise ValueError("string argument should contain only ASCII characters") + elif isinstance(s, bytes_types): + return s + else: + raise TypeError("argument should be bytes or ASCII string, not %s" % s.__class__.__name__) + + +def _maketrans(f, t): + """Re-implement bytes.maketrans() as there is no such function in micropython""" + if len(f) != len(t): + raise ValueError("maketrans arguments must have same length") + translation_table = dict(zip(f, t)) + return translation_table + + +def _translate(input_bytes, trans_table): + """Re-implement bytes.translate() as there is no such function in micropython""" + result = bytearray() + + for byte in input_bytes: + translated_byte = trans_table.get(byte, byte) + result.append(translated_byte) + + return bytes(result) + + +# Base64 encoding/decoding uses binascii + + +def b64encode(s, altchars=None): + """Encode a byte string using Base64. + + s is the byte string to encode. Optional altchars must be a byte + string of length 2 which specifies an alternative alphabet for the + '+' and '/' characters. This allows an application to + e.g. generate url or filesystem safe Base64 strings. + + The encoded byte string is returned. + """ + if not isinstance(s, bytes_types): + raise TypeError("expected bytes, not %s" % s.__class__.__name__) + # Strip off the trailing newline + encoded = binascii.b2a_base64(s)[:-1] + if altchars is not None: + if not isinstance(altchars, bytes_types): + raise TypeError("expected bytes, not %s" % altchars.__class__.__name__) + assert len(altchars) == 2, repr(altchars) + encoded = _translate(encoded, _maketrans(b"+/", altchars)) + return encoded + + +def b64decode(s, altchars=None, validate=False): + """Decode a Base64 encoded byte string. + + s is the byte string to decode. Optional altchars must be a + string of length 2 which specifies the alternative alphabet used + instead of the '+' and '/' characters. + + The decoded string is returned. A binascii.Error is raised if s is + incorrectly padded. + + If validate is False (the default), non-base64-alphabet characters are + discarded prior to the padding check. If validate is True, + non-base64-alphabet characters in the input result in a binascii.Error. + """ + s = _bytes_from_decode_data(s) + if altchars is not None: + altchars = _bytes_from_decode_data(altchars) + assert len(altchars) == 2, repr(altchars) + s = _translate(s, _maketrans(altchars, b"+/")) + if validate and not re.match(b"^[A-Za-z0-9+/]*=*$", s): + raise binascii.Error("Non-base64 digit found") + return binascii.a2b_base64(s) + + +def standard_b64encode(s): + """Encode a byte string using the standard Base64 alphabet. + + s is the byte string to encode. The encoded byte string is returned. + """ + return b64encode(s) + + +def standard_b64decode(s): + """Decode a byte string encoded with the standard Base64 alphabet. + + s is the byte string to decode. The decoded byte string is + returned. binascii.Error is raised if the input is incorrectly + padded or if there are non-alphabet characters present in the + input. + """ + return b64decode(s) + + +# _urlsafe_encode_translation = _maketrans(b'+/', b'-_') +# _urlsafe_decode_translation = _maketrans(b'-_', b'+/') + + +def urlsafe_b64encode(s): + """Encode a byte string using a url-safe Base64 alphabet. + + s is the byte string to encode. The encoded byte string is + returned. The alphabet uses '-' instead of '+' and '_' instead of + '/'. + """ + # return b64encode(s).translate(_urlsafe_encode_translation) + return b64encode(s, b"-_").rstrip(b"\n") + + +def urlsafe_b64decode(s): + """Decode a byte string encoded with the standard Base64 alphabet. + + s is the byte string to decode. The decoded byte string is + returned. binascii.Error is raised if the input is incorrectly + padded or if there are non-alphabet characters present in the + input. + + The alphabet uses '-' instead of '+' and '_' instead of '/'. + """ + # s = _bytes_from_decode_data(s) + # s = s.translate(_urlsafe_decode_translation) + # return b64decode(s) + raise NotImplementedError() + + +# Base32 encoding/decoding must be done in Python +_b32alphabet = { + 0: b"A", + 9: b"J", + 18: b"S", + 27: b"3", + 1: b"B", + 10: b"K", + 19: b"T", + 28: b"4", + 2: b"C", + 11: b"L", + 20: b"U", + 29: b"5", + 3: b"D", + 12: b"M", + 21: b"V", + 30: b"6", + 4: b"E", + 13: b"N", + 22: b"W", + 31: b"7", + 5: b"F", + 14: b"O", + 23: b"X", + 6: b"G", + 15: b"P", + 24: b"Y", + 7: b"H", + 16: b"Q", + 25: b"Z", + 8: b"I", + 17: b"R", + 26: b"2", +} + +_b32tab = [v[0] for k, v in sorted(_b32alphabet.items())] +_b32rev = dict([(v[0], k) for k, v in _b32alphabet.items()]) + + +def b32encode(s): + """Encode a byte string using Base32. + + s is the byte string to encode. The encoded byte string is returned. + """ + if not isinstance(s, bytes_types): + raise TypeError("expected bytes, not %s" % s.__class__.__name__) + quanta, leftover = divmod(len(s), 5) + # Pad the last quantum with zero bits if necessary + if leftover: + s = s + bytes(5 - leftover) # Don't use += ! + quanta += 1 + encoded = bytearray() + for i in range(quanta): + # c1 and c2 are 16 bits wide, c3 is 8 bits wide. The intent of this + # code is to process the 40 bits in units of 5 bits. So we take the 1 + # leftover bit of c1 and tack it onto c2. Then we take the 2 leftover + # bits of c2 and tack them onto c3. The shifts and masks are intended + # to give us values of exactly 5 bits in width. + c1, c2, c3 = struct.unpack("!HHB", s[i * 5 : (i + 1) * 5]) + c2 += (c1 & 1) << 16 # 17 bits wide + c3 += (c2 & 3) << 8 # 10 bits wide + encoded += bytes( + [ + _b32tab[c1 >> 11], # bits 1 - 5 + _b32tab[(c1 >> 6) & 0x1F], # bits 6 - 10 + _b32tab[(c1 >> 1) & 0x1F], # bits 11 - 15 + _b32tab[c2 >> 12], # bits 16 - 20 (1 - 5) + _b32tab[(c2 >> 7) & 0x1F], # bits 21 - 25 (6 - 10) + _b32tab[(c2 >> 2) & 0x1F], # bits 26 - 30 (11 - 15) + _b32tab[c3 >> 5], # bits 31 - 35 (1 - 5) + _b32tab[c3 & 0x1F], # bits 36 - 40 (1 - 5) + ] + ) + # Adjust for any leftover partial quanta + if leftover == 1: + encoded = encoded[:-6] + b"======" + elif leftover == 2: + encoded = encoded[:-4] + b"====" + elif leftover == 3: + encoded = encoded[:-3] + b"===" + elif leftover == 4: + encoded = encoded[:-1] + b"=" + return bytes(encoded) + + +def b32decode(s, casefold=False, map01=None): + """Decode a Base32 encoded byte string. + + s is the byte string to decode. Optional casefold is a flag + specifying whether a lowercase alphabet is acceptable as input. + For security purposes, the default is False. + + RFC 3548 allows for optional mapping of the digit 0 (zero) to the + letter O (oh), and for optional mapping of the digit 1 (one) to + either the letter I (eye) or letter L (el). The optional argument + map01 when not None, specifies which letter the digit 1 should be + mapped to (when map01 is not None, the digit 0 is always mapped to + the letter O). For security purposes the default is None, so that + 0 and 1 are not allowed in the input. + + The decoded byte string is returned. binascii.Error is raised if + the input is incorrectly padded or if there are non-alphabet + characters present in the input. + """ + s = _bytes_from_decode_data(s) + quanta, leftover = divmod(len(s), 8) + if leftover: + raise binascii.Error("Incorrect padding") + # Handle section 2.4 zero and one mapping. The flag map01 will be either + # False, or the character to map the digit 1 (one) to. It should be + # either L (el) or I (eye). + if map01 is not None: + map01 = _bytes_from_decode_data(map01) + assert len(map01) == 1, repr(map01) + s = _translate(s, _maketrans(b"01", b"O" + map01)) + if casefold: + s = s.upper() + # Strip off pad characters from the right. We need to count the pad + # characters because this will tell us how many null bytes to remove from + # the end of the decoded string. + padchars = s.find(b"=") + if padchars > 0: + padchars = len(s) - padchars + s = s[:-padchars] + else: + padchars = 0 + + # Now decode the full quanta + parts = [] + acc = 0 + shift = 35 + for c in s: + val = _b32rev.get(c) + if val is None: + raise binascii.Error("Non-base32 digit found") + acc += _b32rev[c] << shift + shift -= 5 + if shift < 0: + parts.append(binascii.unhexlify(bytes("%010x" % acc, "ascii"))) + acc = 0 + shift = 35 + # Process the last, partial quanta + last = binascii.unhexlify(bytes("%010x" % acc, "ascii")) + if padchars == 0: + last = b"" # No characters + elif padchars == 1: + last = last[:-1] + elif padchars == 3: + last = last[:-2] + elif padchars == 4: + last = last[:-3] + elif padchars == 6: + last = last[:-4] + else: + raise binascii.Error("Incorrect padding") + parts.append(last) + return b"".join(parts) + + +# RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns +# lowercase. The RFC also recommends against accepting input case +# insensitively. +def b16encode(s): + """Encode a byte string using Base16. + + s is the byte string to encode. The encoded byte string is returned. + """ + if not isinstance(s, bytes_types): + raise TypeError("expected bytes, not %s" % s.__class__.__name__) + return binascii.hexlify(s).upper() + + +def b16decode(s, casefold=False): + """Decode a Base16 encoded byte string. + + s is the byte string to decode. Optional casefold is a flag + specifying whether a lowercase alphabet is acceptable as input. + For security purposes, the default is False. + + The decoded byte string is returned. binascii.Error is raised if + s were incorrectly padded or if there are non-alphabet characters + present in the string. + """ + s = _bytes_from_decode_data(s) + if casefold: + s = s.upper() + if re.search(b"[^0-9A-F]", s): + raise binascii.Error("Non-base16 digit found") + return binascii.unhexlify(s) + + +# Legacy interface. This code could be cleaned up since I don't believe +# binascii has any line length limitations. It just doesn't seem worth it +# though. The files should be opened in binary mode. + +MAXLINESIZE = 76 # Excluding the CRLF +MAXBINSIZE = (MAXLINESIZE // 4) * 3 + + +def encode(input, output): + """Encode a file; input and output are binary files.""" + while True: + s = input.read(MAXBINSIZE) + if not s: + break + while len(s) < MAXBINSIZE: + ns = input.read(MAXBINSIZE - len(s)) + if not ns: + break + s += ns + line = binascii.b2a_base64(s) + output.write(line) + + +def decode(input, output): + """Decode a file; input and output are binary files.""" + while True: + line = input.readline() + if not line: + break + s = binascii.a2b_base64(line) + output.write(s) + + +def encodebytes(s): + """Encode a bytestring into a bytestring containing multiple lines + of base-64 data.""" + if not isinstance(s, bytes_types): + raise TypeError("expected bytes, not %s" % s.__class__.__name__) + pieces = [] + for i in range(0, len(s), MAXBINSIZE): + chunk = s[i : i + MAXBINSIZE] + pieces.append(binascii.b2a_base64(chunk)) + return b"".join(pieces) + + +def encodestring(s): + """Legacy alias of encodebytes().""" + import warnings + + warnings.warn("encodestring() is a deprecated alias, use encodebytes()", DeprecationWarning, 2) + return encodebytes(s) + + +def decodebytes(s): + """Decode a bytestring of base-64 data into a bytestring.""" + if not isinstance(s, bytes_types): + raise TypeError("expected bytes, not %s" % s.__class__.__name__) + return binascii.a2b_base64(s) + + +def decodestring(s): + """Legacy alias of decodebytes().""" + import warnings + + warnings.warn("decodestring() is a deprecated alias, use decodebytes()", DeprecationWarning, 2) + return decodebytes(s) + + +# Usable as a script... +def main(): + """Small main program""" + import sys, getopt + + try: + opts, args = getopt.getopt(sys.argv[1:], "deut") + except getopt.error as msg: + sys.stdout = sys.stderr + print(msg) + print( + """usage: %s [-d|-e|-u|-t] [file|-] + -d, -u: decode + -e: encode (default) + -t: encode and decode string 'Aladdin:open sesame'""" + % sys.argv[0] + ) + sys.exit(2) + func = encode + for o, a in opts: + if o == "-e": + func = encode + if o == "-d": + func = decode + if o == "-u": + func = decode + if o == "-t": + test() + return + if args and args[0] != "-": + with open(args[0], "rb") as f: + func(f, sys.stdout.buffer) + else: + func(sys.stdin.buffer, sys.stdout.buffer) + + +def test(): + s0 = b"Aladdin:open sesame" + print(repr(s0)) + s1 = encodebytes(s0) + print(repr(s1)) + s2 = decodebytes(s1) + print(repr(s2)) + assert s0 == s2 + + +if __name__ == "__main__": + main() diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/base64.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/base64.pyi new file mode 100644 index 000000000..67bcd556d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/base64.pyi @@ -0,0 +1,133 @@ +__all__ = [ + "encode", + "decode", + "encodebytes", + "decodebytes", + "b64encode", + "b64decode", + "b32encode", + "b32decode", + "b16encode", + "b16decode", + "standard_b64encode", + "standard_b64decode", + "urlsafe_b64encode", + "urlsafe_b64decode", +] + +def b64encode(s, altchars=None): + """Encode a byte string using Base64. + + s is the byte string to encode. Optional altchars must be a byte + string of length 2 which specifies an alternative alphabet for the + '+' and '/' characters. This allows an application to + e.g. generate url or filesystem safe Base64 strings. + + The encoded byte string is returned. + """ + +def b64decode(s, altchars=None, validate: bool = False): + """Decode a Base64 encoded byte string. + + s is the byte string to decode. Optional altchars must be a + string of length 2 which specifies the alternative alphabet used + instead of the '+' and '/' characters. + + The decoded string is returned. A binascii.Error is raised if s is + incorrectly padded. + + If validate is False (the default), non-base64-alphabet characters are + discarded prior to the padding check. If validate is True, + non-base64-alphabet characters in the input result in a binascii.Error. + """ + +def standard_b64encode(s): + """Encode a byte string using the standard Base64 alphabet. + + s is the byte string to encode. The encoded byte string is returned. + """ + +def standard_b64decode(s): + """Decode a byte string encoded with the standard Base64 alphabet. + + s is the byte string to decode. The decoded byte string is + returned. binascii.Error is raised if the input is incorrectly + padded or if there are non-alphabet characters present in the + input. + """ + +def urlsafe_b64encode(s): + """Encode a byte string using a url-safe Base64 alphabet. + + s is the byte string to encode. The encoded byte string is + returned. The alphabet uses '-' instead of '+' and '_' instead of + '/'. + """ + +def urlsafe_b64decode(s) -> None: + """Decode a byte string encoded with the standard Base64 alphabet. + + s is the byte string to decode. The decoded byte string is + returned. binascii.Error is raised if the input is incorrectly + padded or if there are non-alphabet characters present in the + input. + + The alphabet uses '-' instead of '+' and '_' instead of '/'. + """ + +def b32encode(s): + """Encode a byte string using Base32. + + s is the byte string to encode. The encoded byte string is returned. + """ + +def b32decode(s, casefold: bool = False, map01=None): + """Decode a Base32 encoded byte string. + + s is the byte string to decode. Optional casefold is a flag + specifying whether a lowercase alphabet is acceptable as input. + For security purposes, the default is False. + + RFC 3548 allows for optional mapping of the digit 0 (zero) to the + letter O (oh), and for optional mapping of the digit 1 (one) to + either the letter I (eye) or letter L (el). The optional argument + map01 when not None, specifies which letter the digit 1 should be + mapped to (when map01 is not None, the digit 0 is always mapped to + the letter O). For security purposes the default is None, so that + 0 and 1 are not allowed in the input. + + The decoded byte string is returned. binascii.Error is raised if + the input is incorrectly padded or if there are non-alphabet + characters present in the input. + """ + +def b16encode(s): + """Encode a byte string using Base16. + + s is the byte string to encode. The encoded byte string is returned. + """ + +def b16decode(s, casefold: bool = False): + """Decode a Base16 encoded byte string. + + s is the byte string to decode. Optional casefold is a flag + specifying whether a lowercase alphabet is acceptable as input. + For security purposes, the default is False. + + The decoded byte string is returned. binascii.Error is raised if + s were incorrectly padded or if there are non-alphabet characters + present in the string. + """ + +def encode(input, output) -> None: + """Encode a file; input and output are binary files.""" + +def decode(input, output) -> None: + """Decode a file; input and output are binary files.""" + +def encodebytes(s): + """Encode a bytestring into a bytestring containing multiple lines + of base-64 data.""" + +def decodebytes(s): + """Decode a bytestring of base-64 data into a bytestring.""" diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/binascii.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/binascii.py new file mode 100644 index 000000000..f2ec39e84 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/binascii.py @@ -0,0 +1,362 @@ +from ubinascii import * + +if not "unhexlify" in globals(): + + def unhexlify(data): + if len(data) % 2 != 0: + raise ValueError("Odd-length string") + + return bytes([int(data[i : i + 2], 16) for i in range(0, len(data), 2)]) + + +b2a_hex = hexlify +a2b_hex = unhexlify + +# ____________________________________________________________ + +PAD = "=" + +table_a2b_base64 = [ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 62, + -1, + -1, + -1, + 63, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + -1, + -1, + -1, + -1, + -1, + -1, # Note PAD->-1 here + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + -1, + -1, + -1, + -1, + -1, + -1, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, +] + + +def _transform(n): + if n == -1: + return "\xff" + else: + return chr(n) + + +table_a2b_base64 = "".join(map(_transform, table_a2b_base64)) +assert len(table_a2b_base64) == 256 + + +def a2b_base64(ascii): + "Decode a line of base64 data." + + res = [] + quad_pos = 0 + leftchar = 0 + leftbits = 0 + last_char_was_a_pad = False + + for c in ascii: + c = chr(c) + if c == PAD: + if quad_pos > 2 or (quad_pos == 2 and last_char_was_a_pad): + break # stop on 'xxx=' or on 'xx==' + last_char_was_a_pad = True + else: + n = ord(table_a2b_base64[ord(c)]) + if n == 0xFF: + continue # ignore strange characters + # + # Shift it in on the low end, and see if there's + # a byte ready for output. + quad_pos = (quad_pos + 1) & 3 + leftchar = (leftchar << 6) | n + leftbits += 6 + # + if leftbits >= 8: + leftbits -= 8 + res.append((leftchar >> leftbits).to_bytes(1, "big")) + leftchar &= (1 << leftbits) - 1 + # + last_char_was_a_pad = False + else: + if leftbits != 0: + raise Exception("Incorrect padding") + + return b"".join(res) + + +# ____________________________________________________________ + +table_b2a_base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + + +def b2a_base64(bin, newline=True): + "Base64-code line of data." + + newlength = (len(bin) + 2) // 3 + newlength = newlength * 4 + 1 + res = [] + + leftchar = 0 + leftbits = 0 + for c in bin: + # Shift into our buffer, and output any 6bits ready + leftchar = (leftchar << 8) | c + leftbits += 8 + res.append(table_b2a_base64[(leftchar >> (leftbits - 6)) & 0x3F]) + leftbits -= 6 + if leftbits >= 6: + res.append(table_b2a_base64[(leftchar >> (leftbits - 6)) & 0x3F]) + leftbits -= 6 + # + if leftbits == 2: + res.append(table_b2a_base64[(leftchar & 3) << 4]) + res.append(PAD) + res.append(PAD) + elif leftbits == 4: + res.append(table_b2a_base64[(leftchar & 0xF) << 2]) + res.append(PAD) + if newline: + res.append("\n") + return "".join(res).encode("ascii") diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/binascii.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/binascii.pyi new file mode 100644 index 000000000..daf86513f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/binascii.pyi @@ -0,0 +1,44 @@ +""" +Binary/ASCII conversions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/binascii.html + +CPython module: :mod:`python:binascii` https://docs.python.org/3/library/binascii.html . + +This module implements conversions between binary data and various +encodings of it in ASCII form (in both directions). +""" + +from __future__ import annotations +from ubinascii import * +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def unhexlify(data) -> bytes: + """ + Convert hexadecimal data to binary representation. Returns bytes string. + (i.e. inverse of hexlify) + """ + ... + +b2a_hex = hexlify +a2b_hex = unhexlify +PAD: str +table_a2b_base64: Incomplete + +def _transform(n): ... +def a2b_base64(ascii) -> bytes: + """ + Decode base64-encoded data, ignoring invalid characters in the input. + Conforms to `RFC 2045 s.6.8 `_. + Returns a bytes object. + """ + +table_b2a_base64: str + +def b2a_base64(bin, newline: bool = True) -> bytes: + """ + Encode binary data in base64 format, as in `RFC 3548 + `_. Returns the encoded data + followed by a newline character if newline is true, as a bytes object. + """ diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/__init__.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/__init__.py new file mode 100644 index 000000000..36dfc1c41 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/__init__.py @@ -0,0 +1,12 @@ +# Replace built-in collections module. +from ucollections import * + +# Provide optional dependencies (which may be installed separately). +try: + from .defaultdict import defaultdict +except ImportError: + pass + + +class MutableMapping: + pass diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/__init__.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/__init__.pyi new file mode 100644 index 000000000..4025e520a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/__init__.pyi @@ -0,0 +1,21 @@ +""" +Collection and container types. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/collections.html + +CPython module: :mod:`python:collections` https://docs.python.org/3/library/collections.html . + +This module implements advanced collection and container types to +hold/accumulate various objects. +""" +from __future__ import annotations +from ucollections import * +from .defaultdict import defaultdict as defaultdict +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_KT = TypeVar("_KT") +_VT = TypeVar("_VT") +_T = TypeVar("_T") + +class MutableMapping: ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/defaultdict.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/defaultdict.py new file mode 100644 index 000000000..2d5383282 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/defaultdict.py @@ -0,0 +1,35 @@ +class defaultdict: + @staticmethod + def __new__(cls, default_factory=None, **kwargs): + # Some code (e.g. urllib.urlparse) expects that basic defaultdict + # functionality will be available to subclasses without them + # calling __init__(). + self = super(defaultdict, cls).__new__(cls) + self.d = {} + return self + + def __init__(self, default_factory=None, **kwargs): + self.d = kwargs + self.default_factory = default_factory + + def __getitem__(self, key): + try: + return self.d[key] + except KeyError: + v = self.__missing__(key) + self.d[key] = v + return v + + def __setitem__(self, key, v): + self.d[key] = v + + def __delitem__(self, key): + del self.d[key] + + def __contains__(self, key): + return key in self.d + + def __missing__(self, key): + if self.default_factory is None: + raise KeyError(key) + return self.default_factory() diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/defaultdict.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/defaultdict.pyi new file mode 100644 index 000000000..31002d4d2 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/collections/defaultdict.pyi @@ -0,0 +1,13 @@ +from _typeshed import Incomplete + +class defaultdict: + d: Incomplete + @staticmethod + def __new__(cls, default_factory=None, **kwargs): ... + default_factory: Incomplete + def __init__(self, default_factory=None, **kwargs) -> None: ... + def __getitem__(self, key): ... + def __setitem__(self, key, v) -> None: ... + def __delitem__(self, key) -> None: ... + def __contains__(self, key) -> bool: ... + def __missing__(self, key): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/copy.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/copy.py new file mode 100644 index 000000000..0a9283777 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/copy.py @@ -0,0 +1,380 @@ +"""Generic (shallow and deep) copying operations. + +Interface summary: + + import copy + + x = copy.copy(y) # make a shallow copy of y + x = copy.deepcopy(y) # make a deep copy of y + +For module specific errors, copy.Error is raised. + +The difference between shallow and deep copying is only relevant for +compound objects (objects that contain other objects, like lists or +class instances). + +- A shallow copy constructs a new compound object and then (to the + extent possible) inserts *the same objects* into it that the + original contains. + +- A deep copy constructs a new compound object and then, recursively, + inserts *copies* into it of the objects found in the original. + +Two problems often exist with deep copy operations that don't exist +with shallow copy operations: + + a) recursive objects (compound objects that, directly or indirectly, + contain a reference to themselves) may cause a recursive loop + + b) because deep copy copies *everything* it may copy too much, e.g. + administrative data structures that should be shared even between + copies + +Python's deep copy operation avoids these problems by: + + a) keeping a table of objects already copied during the current + copying pass + + b) letting user-defined classes override the copying operation or the + set of components copied + +This version does not copy types like module, class, function, method, +nor stack trace, stack frame, nor file, socket, window, nor array, nor +any similar types. + +Classes can use the same interfaces to control copying that they use +to control pickling: they can define methods called __getinitargs__(), +__getstate__() and __setstate__(). See the documentation for module +"pickle" for information on these methods. +""" + +import types + +# import weakref +# from copyreg import dispatch_table +# import builtins + + +class Error(Exception): + pass + + +error = Error # backward compatibility + +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None + +try: + from org.python.core import PyStringMap +except ImportError: + PyStringMap = None + +__all__ = ["Error", "copy", "deepcopy"] + + +def copy(x): + """Shallow copy operation on arbitrary Python objects. + + See the module's __doc__ string for more info. + """ + + cls = type(x) + + copier = _copy_dispatch.get(cls) + if copier: + return copier(x) + + copier = getattr(cls, "__copy__", None) + if copier: + return copier(x) + + raise Error("un(shallow)copyable object of type %s" % cls) + + dispatch_table = {} + reductor = dispatch_table.get(cls) + if reductor: + rv = reductor(x) + else: + reductor = getattr(x, "__reduce_ex__", None) + if reductor: + rv = reductor(2) + else: + reductor = getattr(x, "__reduce__", None) + if reductor: + rv = reductor() + else: + raise Error("un(shallow)copyable object of type %s" % cls) + + return _reconstruct(x, rv, 0) + + +_copy_dispatch = d = {} + + +def _copy_immutable(x): + return x + + +for t in ( + type(None), + int, + float, + bool, + str, + tuple, + type, + range, + types.BuiltinFunctionType, + type(Ellipsis), + types.FunctionType, +): + d[t] = _copy_immutable +t = getattr(types, "CodeType", None) +if t is not None: + d[t] = _copy_immutable +# for name in ("complex", "unicode"): +# t = getattr(builtins, name, None) +# if t is not None: +# d[t] = _copy_immutable + + +def _copy_with_constructor(x): + return type(x)(x) + + +for t in (list, dict, set): + d[t] = _copy_with_constructor +if OrderedDict is not None: + d[OrderedDict] = _copy_with_constructor + + +def _copy_with_copy_method(x): + return x.copy() + + +if PyStringMap is not None: + d[PyStringMap] = _copy_with_copy_method + +del d + + +def deepcopy(x, memo=None, _nil=[]): + """Deep copy operation on arbitrary Python objects. + + See the module's __doc__ string for more info. + """ + + if memo is None: + memo = {} + + d = id(x) + y = memo.get(d, _nil) + if y is not _nil: + return y + + cls = type(x) + + copier = _deepcopy_dispatch.get(cls) + if copier: + y = copier(x, memo) + else: + try: + issc = issubclass(cls, type) + except TypeError: # cls is not a class (old Boost; see SF #502085) + issc = 0 + if issc: + y = _deepcopy_atomic(x, memo) + else: + copier = getattr(x, "__deepcopy__", None) + if copier: + y = copier(memo) + else: + reductor = dispatch_table.get(cls) + if reductor: + rv = reductor(x) + else: + reductor = getattr(x, "__reduce_ex__", None) + if reductor: + rv = reductor(2) + else: + reductor = getattr(x, "__reduce__", None) + if reductor: + rv = reductor() + else: + raise Error("un(deep)copyable object of type %s" % cls) + y = _reconstruct(x, rv, 1, memo) + + # If is its own copy, don't memoize. + if y is not x: + memo[d] = y + _keep_alive(x, memo) # Make sure x lives at least as long as d + return y + + +_deepcopy_dispatch = d = {} + + +def _deepcopy_atomic(x, memo): + return x + + +d[type(None)] = _deepcopy_atomic +d[type(Ellipsis)] = _deepcopy_atomic +d[int] = _deepcopy_atomic +d[float] = _deepcopy_atomic +d[bool] = _deepcopy_atomic +try: + d[complex] = _deepcopy_atomic +except NameError: + pass +d[bytes] = _deepcopy_atomic +d[str] = _deepcopy_atomic +try: + d[types.CodeType] = _deepcopy_atomic +except AttributeError: + pass +d[type] = _deepcopy_atomic +d[range] = _deepcopy_atomic +d[types.BuiltinFunctionType] = _deepcopy_atomic +d[types.FunctionType] = _deepcopy_atomic +# d[weakref.ref] = _deepcopy_atomic + + +def _deepcopy_list(x, memo): + y = [] + memo[id(x)] = y + for a in x: + y.append(deepcopy(a, memo)) + return y + + +d[list] = _deepcopy_list + + +def _deepcopy_tuple(x, memo): + y = [] + for a in x: + y.append(deepcopy(a, memo)) + # We're not going to put the tuple in the memo, but it's still important we + # check for it, in case the tuple contains recursive mutable structures. + try: + return memo[id(x)] + except KeyError: + pass + for i in range(len(x)): + if x[i] is not y[i]: + y = tuple(y) + break + else: + y = x + return y + + +d[tuple] = _deepcopy_tuple + + +def _deepcopy_dict(x, memo): + y = type(x)() + memo[id(x)] = y + for key, value in x.items(): + y[deepcopy(key, memo)] = deepcopy(value, memo) + return y + + +d[dict] = _deepcopy_dict +if OrderedDict is not None: + d[OrderedDict] = _deepcopy_dict +if PyStringMap is not None: + d[PyStringMap] = _deepcopy_dict + + +def _deepcopy_method(x, memo): # Copy instance methods + return type(x)(x.__func__, deepcopy(x.__self__, memo)) + + +_deepcopy_dispatch[types.MethodType] = _deepcopy_method + + +def _keep_alive(x, memo): + """Keeps a reference to the object x in the memo. + + Because we remember objects by their id, we have + to assure that possibly temporary objects are kept + alive by referencing them. + We store a reference at the id of the memo, which should + normally not be used unless someone tries to deepcopy + the memo itself... + """ + try: + memo[id(memo)].append(x) + except KeyError: + # aha, this is the first one :-) + memo[id(memo)] = [x] + + +def _reconstruct(x, info, deep, memo=None): + if isinstance(info, str): + return x + assert isinstance(info, tuple) + if memo is None: + memo = {} + n = len(info) + assert n in (2, 3, 4, 5) + callable, args = info[:2] + if n > 2: + state = info[2] + else: + state = {} + if n > 3: + listiter = info[3] + else: + listiter = None + if n > 4: + dictiter = info[4] + else: + dictiter = None + if deep: + args = deepcopy(args, memo) + y = callable(*args) + memo[id(x)] = y + + if state: + if deep: + state = deepcopy(state, memo) + if hasattr(y, "__setstate__"): + y.__setstate__(state) + else: + if isinstance(state, tuple) and len(state) == 2: + state, slotstate = state + else: + slotstate = None + if state is not None: + y.__dict__.update(state) + if slotstate is not None: + for key, value in slotstate.items(): + setattr(y, key, value) + + if listiter is not None: + for item in listiter: + if deep: + item = deepcopy(item, memo) + y.append(item) + if dictiter is not None: + for key, value in dictiter: + if deep: + key = deepcopy(key, memo) + value = deepcopy(value, memo) + y[key] = value + return y + + +del d + +del types + + +# Helper for instance creation without calling __init__ +class _EmptyClass: + pass diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/copy.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/copy.pyi new file mode 100644 index 000000000..2ea671149 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/copy.pyi @@ -0,0 +1,19 @@ +__all__ = ["Error", "copy", "deepcopy"] + +class Error(Exception): ... + +error = Error + +def copy(x): + """Shallow copy operation on arbitrary Python objects. + + See the module's __doc__ string for more info. + """ + +def deepcopy(x, memo=None, _nil=[]): + """Deep copy operation on arbitrary Python objects. + + See the module's __doc__ string for more info. + """ + +class _EmptyClass: ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/datetime.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/datetime.py new file mode 100644 index 000000000..91a752d3c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/datetime.py @@ -0,0 +1,861 @@ +# datetime.py + +import time as _tmod + +_DBM = (0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334) +_DIM = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) +_TIME_SPEC = ("auto", "hours", "minutes", "seconds", "milliseconds", "microseconds") + + +def _leap(y): + return y % 4 == 0 and (y % 100 != 0 or y % 400 == 0) + + +def _dby(y): + # year -> number of days before January 1st of year. + Y = y - 1 + return Y * 365 + Y // 4 - Y // 100 + Y // 400 + + +def _dim(y, m): + # year, month -> number of days in that month in that year. + if m == 2 and _leap(y): + return 29 + return _DIM[m] + + +def _dbm(y, m): + # year, month -> number of days in year preceding first day of month. + return _DBM[m] + (m > 2 and _leap(y)) + + +def _ymd2o(y, m, d): + # y, month, day -> ordinal, considering 01-Jan-0001 as day 1. + return _dby(y) + _dbm(y, m) + d + + +def _o2ymd(n): + # ordinal -> (year, month, day), considering 01-Jan-0001 as day 1. + n -= 1 + n400, n = divmod(n, 146_097) + y = n400 * 400 + 1 + n100, n = divmod(n, 36_524) + n4, n = divmod(n, 1_461) + n1, n = divmod(n, 365) + y += n100 * 100 + n4 * 4 + n1 + if n1 == 4 or n100 == 4: + return y - 1, 12, 31 + m = (n + 50) >> 5 + prec = _dbm(y, m) + if prec > n: + m -= 1 + prec -= _dim(y, m) + n -= prec + return y, m, n + 1 + + +MINYEAR = 1 +MAXYEAR = 9_999 + + +class timedelta: + def __init__(self, days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0): + s = (((weeks * 7 + days) * 24 + hours) * 60 + minutes) * 60 + seconds + self._us = round((s * 1000 + milliseconds) * 1000 + microseconds) + + def __repr__(self): + return "datetime.timedelta(microseconds={})".format(self._us) + + def total_seconds(self): + return self._us / 1_000_000 + + @property + def days(self): + return self._tuple(2)[0] + + @property + def seconds(self): + return self._tuple(3)[1] + + @property + def microseconds(self): + return self._tuple(3)[2] + + def __add__(self, other): + if isinstance(other, datetime): + return other.__add__(self) + else: + us = other._us + return timedelta(0, 0, self._us + us) + + def __sub__(self, other): + return timedelta(0, 0, self._us - other._us) + + def __neg__(self): + return timedelta(0, 0, -self._us) + + def __pos__(self): + return self + + def __abs__(self): + return -self if self._us < 0 else self + + def __mul__(self, other): + return timedelta(0, 0, round(other * self._us)) + + __rmul__ = __mul__ + + def __truediv__(self, other): + if isinstance(other, timedelta): + return self._us / other._us + else: + return timedelta(0, 0, round(self._us / other)) + + def __floordiv__(self, other): + if isinstance(other, timedelta): + return self._us // other._us + else: + return timedelta(0, 0, int(self._us // other)) + + def __mod__(self, other): + return timedelta(0, 0, self._us % other._us) + + def __divmod__(self, other): + q, r = divmod(self._us, other._us) + return q, timedelta(0, 0, r) + + def __eq__(self, other): + return self._us == other._us + + def __le__(self, other): + return self._us <= other._us + + def __lt__(self, other): + return self._us < other._us + + def __ge__(self, other): + return self._us >= other._us + + def __gt__(self, other): + return self._us > other._us + + def __bool__(self): + return self._us != 0 + + def __str__(self): + return self._format(0x40) + + def __hash__(self): + if not hasattr(self, "_hash"): + self._hash = hash(self._us) + return self._hash + + def isoformat(self): + return self._format(0) + + def _format(self, spec=0): + if self._us >= 0: + td = self + g = "" + else: + td = -self + g = "-" + d, h, m, s, us = td._tuple(5) + ms, us = divmod(us, 1000) + r = "" + if spec & 0x40: + spec &= ~0x40 + hr = str(h) + else: + hr = f"{h:02d}" + if spec & 0x20: + spec &= ~0x20 + spec |= 0x10 + r += "UTC" + if spec & 0x10: + spec &= ~0x10 + if not g: + g = "+" + if d: + p = "s" if d > 1 else "" + r += f"{g}{d} day{p}, " + g = "" + if spec == 0: + spec = 5 if (ms or us) else 3 + if spec >= 1 or h: + r += f"{g}{hr}" + if spec >= 2 or m: + r += f":{m:02d}" + if spec >= 3 or s: + r += f":{s:02d}" + if spec >= 4 or ms: + r += f".{ms:03d}" + if spec >= 5 or us: + r += f"{us:03d}" + return r + + def tuple(self): + return self._tuple(5) + + def _tuple(self, n): + d, us = divmod(self._us, 86_400_000_000) + if n == 2: + return d, us + s, us = divmod(us, 1_000_000) + if n == 3: + return d, s, us + h, s = divmod(s, 3600) + m, s = divmod(s, 60) + return d, h, m, s, us + + +timedelta.min = timedelta(days=-999_999_999) +timedelta.max = timedelta(days=999_999_999, hours=23, minutes=59, seconds=59, microseconds=999_999) +timedelta.resolution = timedelta(microseconds=1) + + +class tzinfo: + # abstract class + def tzname(self, dt): + raise NotImplementedError + + def utcoffset(self, dt): + raise NotImplementedError + + def dst(self, dt): + raise NotImplementedError + + def fromutc(self, dt): + if dt._tz is not self: + raise ValueError + + # See original datetime.py for an explanation of this algorithm. + dtoff = dt.utcoffset() + dtdst = dt.dst() + delta = dtoff - dtdst + if delta: + dt += delta + dtdst = dt.dst() + return dt + dtdst + + def isoformat(self, dt): + return self.utcoffset(dt)._format(0x12) + + +class timezone(tzinfo): + def __init__(self, offset, name=None): + if not (abs(offset._us) < 86_400_000_000): + raise ValueError + self._offset = offset + self._name = name + + def __repr__(self): + return "datetime.timezone({}, {})".format(repr(self._offset), repr(self._name)) + + def __eq__(self, other): + if isinstance(other, timezone): + return self._offset == other._offset + return NotImplemented + + def __str__(self): + return self.tzname(None) + + def __hash__(self): + if not hasattr(self, "_hash"): + self._hash = hash((self._offset, self._name)) + return self._hash + + def utcoffset(self, dt): + return self._offset + + def dst(self, dt): + return None + + def tzname(self, dt): + if self._name: + return self._name + return self._offset._format(0x22) + + def fromutc(self, dt): + return dt + self._offset + + +timezone.utc = timezone(timedelta(0)) + + +def _date(y, m, d): + if MINYEAR <= y <= MAXYEAR and 1 <= m <= 12 and 1 <= d <= _dim(y, m): + return _ymd2o(y, m, d) + elif y == 0 and m == 0 and 1 <= d <= 3_652_059: + return d + else: + raise ValueError + + +def _iso2d(s): # ISO -> date + if len(s) < 10 or s[4] != "-" or s[7] != "-": + raise ValueError + return int(s[0:4]), int(s[5:7]), int(s[8:10]) + + +def _d2iso(o): # date -> ISO + return "%04d-%02d-%02d" % _o2ymd(o) + + +class date: + def __init__(self, year, month, day): + self._ord = _date(year, month, day) + + @classmethod + def fromtimestamp(cls, ts): + return cls(*_tmod.localtime(ts)[:3]) + + @classmethod + def today(cls): + return cls(*_tmod.localtime()[:3]) + + @classmethod + def fromordinal(cls, n): + return cls(0, 0, n) + + @classmethod + def fromisoformat(cls, s): + return cls(*_iso2d(s)) + + @property + def year(self): + return self.tuple()[0] + + @property + def month(self): + return self.tuple()[1] + + @property + def day(self): + return self.tuple()[2] + + def toordinal(self): + return self._ord + + def timetuple(self): + y, m, d = self.tuple() + yday = _dbm(y, m) + d + return (y, m, d, 0, 0, 0, self.weekday(), yday, -1) + + def replace(self, year=None, month=None, day=None): + year_, month_, day_ = self.tuple() + if year is None: + year = year_ + if month is None: + month = month_ + if day is None: + day = day_ + return date(year, month, day) + + def __add__(self, other): + return date.fromordinal(self._ord + other.days) + + def __sub__(self, other): + if isinstance(other, date): + return timedelta(days=self._ord - other._ord) + else: + return date.fromordinal(self._ord - other.days) + + def __eq__(self, other): + if isinstance(other, date): + return self._ord == other._ord + else: + return False + + def __le__(self, other): + return self._ord <= other._ord + + def __lt__(self, other): + return self._ord < other._ord + + def __ge__(self, other): + return self._ord >= other._ord + + def __gt__(self, other): + return self._ord > other._ord + + def weekday(self): + return (self._ord + 6) % 7 + + def isoweekday(self): + return self._ord % 7 or 7 + + def isoformat(self): + return _d2iso(self._ord) + + def __repr__(self): + return "datetime.date(0, 0, {})".format(self._ord) + + __str__ = isoformat + + def __hash__(self): + if not hasattr(self, "_hash"): + self._hash = hash(self._ord) + return self._hash + + def tuple(self): + return _o2ymd(self._ord) + + +date.min = date(MINYEAR, 1, 1) +date.max = date(MAXYEAR, 12, 31) +date.resolution = timedelta(days=1) + + +def _time(h, m, s, us, fold): + if (0 <= h < 24 and 0 <= m < 60 and 0 <= s < 60 and 0 <= us < 1_000_000 and (fold == 0 or fold == 1)) or ( + h == 0 and m == 0 and s == 0 and 0 < us < 86_400_000_000 + ): + return timedelta(0, s, us, 0, m, h) + else: + raise ValueError + + +def _iso2t(s): + hour = 0 + minute = 0 + sec = 0 + usec = 0 + tz_sign = "" + tz_hour = 0 + tz_minute = 0 + tz_sec = 0 + tz_usec = 0 + l = len(s) + i = 0 + if l < 2: + raise ValueError + i += 2 + hour = int(s[i - 2 : i]) + if l > i and s[i] == ":": + i += 3 + if l - i < 0: + raise ValueError + minute = int(s[i - 2 : i]) + if l > i and s[i] == ":": + i += 3 + if l - i < 0: + raise ValueError + sec = int(s[i - 2 : i]) + if l > i and s[i] == ".": + i += 4 + if l - i < 0: + raise ValueError + usec = 1000 * int(s[i - 3 : i]) + if l > i and s[i] != "+": + i += 3 + if l - i < 0: + raise ValueError + usec += int(s[i - 3 : i]) + if l > i: + if s[i] not in "+-": + raise ValueError + tz_sign = s[i] + i += 6 + if l - i < 0: + raise ValueError + tz_hour = int(s[i - 5 : i - 3]) + tz_minute = int(s[i - 2 : i]) + if l > i and s[i] == ":": + i += 3 + if l - i < 0: + raise ValueError + tz_sec = int(s[i - 2 : i]) + if l > i and s[i] == ".": + i += 7 + if l - i < 0: + raise ValueError + tz_usec = int(s[i - 6 : i]) + if l != i: + raise ValueError + if tz_sign: + td = timedelta(hours=tz_hour, minutes=tz_minute, seconds=tz_sec, microseconds=tz_usec) + if tz_sign == "-": + td = -td + tz = timezone(td) + else: + tz = None + return hour, minute, sec, usec, tz + + +def _t2iso(td, timespec, dt, tz): + s = td._format(_TIME_SPEC.index(timespec)) + if tz is not None: + s += tz.isoformat(dt) + return s + + +class time: + def __init__(self, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0): + self._td = _time(hour, minute, second, microsecond, fold) + self._tz = tzinfo + self._fd = fold + + @classmethod + def fromisoformat(cls, s): + return cls(*_iso2t(s)) + + @property + def hour(self): + return self.tuple()[0] + + @property + def minute(self): + return self.tuple()[1] + + @property + def second(self): + return self.tuple()[2] + + @property + def microsecond(self): + return self.tuple()[3] + + @property + def tzinfo(self): + return self._tz + + @property + def fold(self): + return self._fd + + def replace(self, hour=None, minute=None, second=None, microsecond=None, tzinfo=True, *, fold=None): + h, m, s, us, tz, fl = self.tuple() + if hour is None: + hour = h + if minute is None: + minute = m + if second is None: + second = s + if microsecond is None: + microsecond = us + if tzinfo is True: + tzinfo = tz + if fold is None: + fold = fl + return time(hour, minute, second, microsecond, tzinfo, fold=fold) + + def isoformat(self, timespec="auto"): + return _t2iso(self._td, timespec, None, self._tz) + + def __repr__(self): + return "datetime.time(microsecond={}, tzinfo={}, fold={})".format(self._td._us, repr(self._tz), self._fd) + + __str__ = isoformat + + def __bool__(self): + return True + + def __eq__(self, other): + if (self._tz == None) ^ (other._tz == None): + return False + return self._sub(other) == 0 + + def __le__(self, other): + return self._sub(other) <= 0 + + def __lt__(self, other): + return self._sub(other) < 0 + + def __ge__(self, other): + return self._sub(other) >= 0 + + def __gt__(self, other): + return self._sub(other) > 0 + + def _sub(self, other): + tz1 = self._tz + if (tz1 is None) ^ (other._tz is None): + raise TypeError + us1 = self._td._us + us2 = other._td._us + if tz1 is not None: + os1 = self.utcoffset()._us + os2 = other.utcoffset()._us + if os1 != os2: + us1 -= os1 + us2 -= os2 + return us1 - us2 + + def __hash__(self): + if not hasattr(self, "_hash"): + # fold doesn't make any difference + self._hash = hash((self._td, self._tz)) + return self._hash + + def utcoffset(self): + return None if self._tz is None else self._tz.utcoffset(None) + + def dst(self): + return None if self._tz is None else self._tz.dst(None) + + def tzname(self): + return None if self._tz is None else self._tz.tzname(None) + + def tuple(self): + d, h, m, s, us = self._td.tuple() + return h, m, s, us, self._tz, self._fd + + +time.min = time(0) +time.max = time(23, 59, 59, 999_999) +time.resolution = timedelta.resolution + + +class datetime: + def __init__(self, year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0): + self._d = _date(year, month, day) + self._t = _time(hour, minute, second, microsecond, fold) + self._tz = tzinfo + self._fd = fold + + @classmethod + def fromtimestamp(cls, ts, tz=None): + if isinstance(ts, float): + ts, us = divmod(round(ts * 1_000_000), 1_000_000) + else: + us = 0 + if tz is None: + raise NotImplementedError + else: + dt = cls(*_tmod.gmtime(ts)[:6], microsecond=us, tzinfo=tz) + dt = tz.fromutc(dt) + return dt + + @classmethod + def now(cls, tz=None): + return cls.fromtimestamp(_tmod.time(), tz) + + @classmethod + def fromordinal(cls, n): + return cls(0, 0, n) + + @classmethod + def fromisoformat(cls, s): + d = _iso2d(s) + if len(s) <= 12: + return cls(*d) + t = _iso2t(s[11:]) + return cls(*(d + t)) + + @classmethod + def combine(cls, date, time, tzinfo=None): + return cls(0, 0, date.toordinal(), 0, 0, 0, time._td._us, tzinfo or time._tz, fold=time._fd) + + @property + def year(self): + return _o2ymd(self._d)[0] + + @property + def month(self): + return _o2ymd(self._d)[1] + + @property + def day(self): + return _o2ymd(self._d)[2] + + @property + def hour(self): + return self._t.tuple()[1] + + @property + def minute(self): + return self._t.tuple()[2] + + @property + def second(self): + return self._t.tuple()[3] + + @property + def microsecond(self): + return self._t.tuple()[4] + + @property + def tzinfo(self): + return self._tz + + @property + def fold(self): + return self._fd + + def __add__(self, other): + us = self._t._us + other._us + d, us = divmod(us, 86_400_000_000) + d += self._d + return datetime(0, 0, d, 0, 0, 0, us, self._tz) + + def __sub__(self, other): + if isinstance(other, timedelta): + return self.__add__(-other) + elif isinstance(other, datetime): + d, us = self._sub(other) + return timedelta(d, 0, us) + else: + raise TypeError + + def _sub(self, other): + # Subtract two datetime instances. + tz1 = self._tz + if (tz1 is None) ^ (other._tz is None): + raise TypeError + dt1 = self + dt2 = other + if tz1 is not None: + os1 = dt1.utcoffset() + os2 = dt2.utcoffset() + if os1 != os2: + dt1 -= os1 + dt2 -= os2 + D = dt1._d - dt2._d + us = dt1._t._us - dt2._t._us + d, us = divmod(us, 86_400_000_000) + return D + d, us + + def __eq__(self, other): + if (self._tz == None) ^ (other._tz == None): + return False + return self._cmp(other) == 0 + + def __le__(self, other): + return self._cmp(other) <= 0 + + def __lt__(self, other): + return self._cmp(other) < 0 + + def __ge__(self, other): + return self._cmp(other) >= 0 + + def __gt__(self, other): + return self._cmp(other) > 0 + + def _cmp(self, other): + # Compare two datetime instances. + d, us = self._sub(other) + if d < 0: + return -1 + if d > 0: + return 1 + + if us < 0: + return -1 + if us > 0: + return 1 + + return 0 + + def date(self): + return date.fromordinal(self._d) + + def time(self): + return time(microsecond=self._t._us, fold=self._fd) + + def timetz(self): + return time(microsecond=self._t._us, tzinfo=self._tz, fold=self._fd) + + def replace( + self, + year=None, + month=None, + day=None, + hour=None, + minute=None, + second=None, + microsecond=None, + tzinfo=True, + *, + fold=None, + ): + Y, M, D, h, m, s, us, tz, fl = self.tuple() + if year is None: + year = Y + if month is None: + month = M + if day is None: + day = D + if hour is None: + hour = h + if minute is None: + minute = m + if second is None: + second = s + if microsecond is None: + microsecond = us + if tzinfo is True: + tzinfo = tz + if fold is None: + fold = fl + return datetime(year, month, day, hour, minute, second, microsecond, tzinfo, fold=fold) + + def astimezone(self, tz=None): + if self._tz is tz: + return self + _tz = self._tz + if _tz is None: + raise NotImplementedError + else: + os = _tz.utcoffset(self) + utc = self - os + utc = utc.replace(tzinfo=tz) + return tz.fromutc(utc) + + def utcoffset(self): + return None if self._tz is None else self._tz.utcoffset(self) + + def dst(self): + return None if self._tz is None else self._tz.dst(self) + + def tzname(self): + return None if self._tz is None else self._tz.tzname(self) + + def timetuple(self): + if self._tz is None: + conv = _tmod.gmtime + epoch = datetime.EPOCH.replace(tzinfo=None) + else: + conv = _tmod.localtime + epoch = datetime.EPOCH + return conv(round((self - epoch).total_seconds())) + + def toordinal(self): + return self._d + + def timestamp(self): + if self._tz is None: + raise NotImplementedError + else: + return (self - datetime.EPOCH).total_seconds() + + def weekday(self): + return (self._d + 6) % 7 + + def isoweekday(self): + return self._d % 7 or 7 + + def isoformat(self, sep="T", timespec="auto"): + return _d2iso(self._d) + sep + _t2iso(self._t, timespec, self, self._tz) + + def __repr__(self): + Y, M, D, h, m, s, us, tz, fold = self.tuple() + tz = repr(tz) + return "datetime.datetime({}, {}, {}, {}, {}, {}, {}, {}, fold={})".format(Y, M, D, h, m, s, us, tz, fold) + + def __str__(self): + return self.isoformat(" ") + + def __hash__(self): + if not hasattr(self, "_hash"): + self._hash = hash((self._d, self._t, self._tz)) + return self._hash + + def tuple(self): + d = _o2ymd(self._d) + t = self._t.tuple()[1:] + return d + t + (self._tz, self._fd) + + +datetime.EPOCH = datetime(*_tmod.gmtime(0)[:6], tzinfo=timezone.utc) diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/datetime.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/datetime.pyi new file mode 100644 index 000000000..66c18dca9 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/datetime.pyi @@ -0,0 +1,229 @@ +from _typeshed import Incomplete + +_DBM: Incomplete +_DIM: Incomplete +_TIME_SPEC: Incomplete + +def _leap(y): ... +def _dby(y): ... +def _dim(y, m): ... +def _dbm(y, m): ... +def _ymd2o(y, m, d): ... +def _o2ymd(n): ... + +MINYEAR: int +MAXYEAR: int + +class timedelta: + _us: Incomplete + def __init__( + self, + days: int = 0, + seconds: int = 0, + microseconds: int = 0, + milliseconds: int = 0, + minutes: int = 0, + hours: int = 0, + weeks: int = 0, + ) -> None: ... + def __repr__(self) -> str: ... + def total_seconds(self): ... + @property + def days(self): ... + @property + def seconds(self): ... + @property + def microseconds(self): ... + def __add__(self, other): ... + def __sub__(self, other): ... + def __neg__(self): ... + def __pos__(self): ... + def __abs__(self): ... + def __mul__(self, other): ... + __rmul__ = __mul__ + def __truediv__(self, other): ... + def __floordiv__(self, other): ... + def __mod__(self, other): ... + def __divmod__(self, other): ... + def __eq__(self, other): ... + def __le__(self, other): ... + def __lt__(self, other): ... + def __ge__(self, other): ... + def __gt__(self, other): ... + def __bool__(self) -> bool: ... + def __str__(self) -> str: ... + _hash: Incomplete + def __hash__(self): ... + def isoformat(self): ... + def _format(self, spec: int = 0): ... + def tuple(self): ... + def _tuple(self, n): ... + +class tzinfo: + def tzname(self, dt) -> None: ... + def utcoffset(self, dt) -> None: ... + def dst(self, dt) -> None: ... + def fromutc(self, dt): ... + def isoformat(self, dt): ... + +class timezone(tzinfo): + _offset: Incomplete + _name: Incomplete + def __init__(self, offset, name=None) -> None: ... + def __repr__(self) -> str: ... + def __eq__(self, other): ... + def __str__(self) -> str: ... + _hash: Incomplete + def __hash__(self): ... + def utcoffset(self, dt): ... + def dst(self, dt) -> None: ... + def tzname(self, dt): ... + def fromutc(self, dt): ... + +def _date(y, m, d): ... +def _iso2d(s): ... +def _d2iso(o): ... + +class date: + _ord: Incomplete + def __init__(self, year, month, day) -> None: ... + @classmethod + def fromtimestamp(cls, ts): ... + @classmethod + def today(cls): ... + @classmethod + def fromordinal(cls, n): ... + @classmethod + def fromisoformat(cls, s): ... + @property + def year(self): ... + @property + def month(self): ... + @property + def day(self): ... + def toordinal(self): ... + def timetuple(self): ... + def replace(self, year=None, month=None, day=None): ... + def __add__(self, other): ... + def __sub__(self, other): ... + def __eq__(self, other): ... + def __le__(self, other): ... + def __lt__(self, other): ... + def __ge__(self, other): ... + def __gt__(self, other): ... + def weekday(self): ... + def isoweekday(self): ... + def isoformat(self): ... + def __repr__(self) -> str: ... + __str__ = isoformat + _hash: Incomplete + def __hash__(self): ... + def tuple(self): ... + +def _time(h, m, s, us, fold): ... +def _iso2t(s): ... +def _t2iso(td, timespec, dt, tz): ... + +class time: + _td: Incomplete + _tz: Incomplete + _fd: Incomplete + def __init__(self, hour: int = 0, minute: int = 0, second: int = 0, microsecond: int = 0, tzinfo=None, *, fold: int = 0) -> None: ... + @classmethod + def fromisoformat(cls, s): ... + @property + def hour(self): ... + @property + def minute(self): ... + @property + def second(self): ... + @property + def microsecond(self): ... + @property + def tzinfo(self): ... + @property + def fold(self): ... + def replace(self, hour=None, minute=None, second=None, microsecond=None, tzinfo: bool = True, *, fold=None): ... + def isoformat(self, timespec: str = "auto"): ... + def __repr__(self) -> str: ... + __str__ = isoformat + def __bool__(self) -> bool: ... + def __eq__(self, other): ... + def __le__(self, other): ... + def __lt__(self, other): ... + def __ge__(self, other): ... + def __gt__(self, other): ... + def _sub(self, other): ... + _hash: Incomplete + def __hash__(self): ... + def utcoffset(self): ... + def dst(self): ... + def tzname(self): ... + def tuple(self): ... + +class datetime: + _d: Incomplete + _t: Incomplete + _tz: Incomplete + _fd: Incomplete + def __init__( + self, year, month, day, hour: int = 0, minute: int = 0, second: int = 0, microsecond: int = 0, tzinfo=None, *, fold: int = 0 + ) -> None: ... + @classmethod + def fromtimestamp(cls, ts, tz=None): ... + @classmethod + def now(cls, tz=None): ... + @classmethod + def fromordinal(cls, n): ... + @classmethod + def fromisoformat(cls, s): ... + @classmethod + def combine(cls, date, time, tzinfo=None): ... + @property + def year(self): ... + @property + def month(self): ... + @property + def day(self): ... + @property + def hour(self): ... + @property + def minute(self): ... + @property + def second(self): ... + @property + def microsecond(self): ... + @property + def tzinfo(self): ... + @property + def fold(self): ... + def __add__(self, other): ... + def __sub__(self, other): ... + def _sub(self, other): ... + def __eq__(self, other): ... + def __le__(self, other): ... + def __lt__(self, other): ... + def __ge__(self, other): ... + def __gt__(self, other): ... + def _cmp(self, other): ... + def date(self): ... + def time(self): ... + def timetz(self): ... + def replace( + self, year=None, month=None, day=None, hour=None, minute=None, second=None, microsecond=None, tzinfo: bool = True, *, fold=None + ): ... + def astimezone(self, tz=None): ... + def utcoffset(self): ... + def dst(self): ... + def tzname(self): ... + def timetuple(self): ... + def toordinal(self): ... + def timestamp(self): ... + def weekday(self): ... + def isoweekday(self): ... + def isoformat(self, sep: str = "T", timespec: str = "auto"): ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... + _hash: Incomplete + def __hash__(self): ... + def tuple(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/fnmatch.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/fnmatch.py new file mode 100644 index 000000000..063442690 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/fnmatch.py @@ -0,0 +1,140 @@ +"""Filename matching with shell patterns. + +fnmatch(FILENAME, PATTERN) matches according to the local convention. +fnmatchcase(FILENAME, PATTERN) always takes case in account. + +The functions operate by translating the pattern into a regular +expression. They cache the compiled regular expressions for speed. + +The function translate(PATTERN) returns a regular expression +corresponding to PATTERN. (It does not compile it.) +""" + +import re + +try: + from os.path import normcase +except ImportError: + + def normcase(s): + """ + From os.path.normcase + Normalize the case of a pathname. On Windows, convert all characters + in the pathname to lowercase, and also convert forward slashes to + backward slashes. On other operating systems, return the path unchanged. + """ + return s + + +__all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] + + +def fnmatch(name, pat): + """Test whether FILENAME matches PATTERN. + + Patterns are Unix shell style: + + * matches everything + ? matches any single character + [seq] matches any character in seq + [!seq] matches any char not in seq + + An initial period in FILENAME is not special. + Both FILENAME and PATTERN are first case-normalized + if the operating system requires it. + If you don't want this, use fnmatchcase(FILENAME, PATTERN). + """ + name = normcase(name) + pat = normcase(pat) + return fnmatchcase(name, pat) + + +# @functools.lru_cache(maxsize=256, typed=True) +def _compile_pattern(pat): + if isinstance(pat, bytes): + pat_str = str(pat, "ISO-8859-1") + res_str = translate(pat_str) + res = bytes(res_str, "ISO-8859-1") + else: + res = translate(pat) + + try: + ptn = re.compile(res) + except ValueError: + # re1.5 doesn't support all regex features + if res.startswith("(?ms)"): + res = res[5:] + if res.endswith("\\Z"): + res = res[:-2] + "$" + ptn = re.compile(res) + + return ptn.match + + +def filter(names, pat): + """Return the subset of the list NAMES that match PAT.""" + result = [] + pat = normcase(pat) + match = _compile_pattern(pat) + for name in names: + if match(normcase(name)): + result.append(name) + return result + + +def fnmatchcase(name, pat): + """Test whether FILENAME matches PATTERN, including case. + + This is a version of fnmatch() which doesn't case-normalize + its arguments. + """ + match = _compile_pattern(pat) + return match(name) is not None + + +def translate(pat): + """Translate a shell PATTERN to a regular expression. + + There is no way to quote meta-characters. + """ + + i, n = 0, len(pat) + res = "" + while i < n: + c = pat[i] + i = i + 1 + if c == "*": + res = res + ".*" + elif c == "?": + res = res + "." + elif c == "[": + j = i + if j < n and pat[j] == "!": + j = j + 1 + if j < n and pat[j] == "]": + j = j + 1 + while j < n and pat[j] != "]": + j = j + 1 + if j >= n: + res = res + "\\[" + else: + stuff = pat[i:j].replace("\\", "\\\\") + i = j + 1 + if stuff[0] == "!": + stuff = "^" + stuff[1:] + elif stuff[0] == "^": + stuff = "\\" + stuff + res = "%s[%s]" % (res, stuff) + else: + try: + res = res + re.escape(c) + except AttributeError: + # Using ure rather than re-pcre + res = res + re_escape(c) + # Original patterns is undefined, see http://bugs.python.org/issue21464 + return "(?ms)" + res + "\Z" + + +def re_escape(pattern): + # Replacement minimal re.escape for ure compatibility + return re.sub(r"([\^\$\.\|\?\*\+\(\)\[\\])", r"\\\1", pattern) diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/fnmatch.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/fnmatch.pyi new file mode 100644 index 000000000..3b89a0e73 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/fnmatch.pyi @@ -0,0 +1,33 @@ +__all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] + +def fnmatch(name, pat): + """Test whether FILENAME matches PATTERN. + + Patterns are Unix shell style: + + * matches everything + ? matches any single character + [seq] matches any character in seq + [!seq] matches any char not in seq + + An initial period in FILENAME is not special. + Both FILENAME and PATTERN are first case-normalized + if the operating system requires it. + If you don't want this, use fnmatchcase(FILENAME, PATTERN). + """ + +def filter(names, pat): + """Return the subset of the list NAMES that match PAT.""" + +def fnmatchcase(name, pat): + """Test whether FILENAME matches PATTERN, including case. + + This is a version of fnmatch() which doesn't case-normalize + its arguments. + """ + +def translate(pat): + """Translate a shell PATTERN to a regular expression. + + There is no way to quote meta-characters. + """ diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/functools.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/functools.py new file mode 100644 index 000000000..b3c368e8a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/functools.py @@ -0,0 +1,28 @@ +def partial(func, *args, **kwargs): + def _partial(*more_args, **more_kwargs): + kw = kwargs.copy() + kw.update(more_kwargs) + return func(*(args + more_args), **kw) + + return _partial + + +def update_wrapper(wrapper, wrapped, assigned=None, updated=None): + # Dummy impl + return wrapper + + +def wraps(wrapped, assigned=None, updated=None): + # Dummy impl + return lambda x: x + + +def reduce(function, iterable, initializer=None): + it = iter(iterable) + if initializer is None: + value = next(it) + else: + value = initializer + for element in it: + value = function(value, element) + return value diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/functools.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/functools.pyi new file mode 100644 index 000000000..6d8418965 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/functools.pyi @@ -0,0 +1,4 @@ +def partial(func, *args, **kwargs): ... +def update_wrapper(wrapper, wrapped, assigned=None, updated=None): ... +def wraps(wrapped, assigned=None, updated=None): ... +def reduce(function, iterable, initializer=None): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/gzip.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/gzip.py new file mode 100644 index 000000000..79a9245e8 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/gzip.py @@ -0,0 +1,29 @@ +# MicroPython gzip module +# MIT license; Copyright (c) 2023 Jim Mussared + +_WBITS = 15 + +import builtins, io, deflate + + +def GzipFile(fileobj): + return deflate.DeflateIO(fileobj, deflate.GZIP, _WBITS) + + +def open(filename, mode="rb"): + return deflate.DeflateIO(builtins.open(filename, mode), deflate.GZIP, _WBITS, True) + + +if hasattr(deflate.DeflateIO, "write"): + + def compress(data): + f = io.BytesIO() + with GzipFile(fileobj=f) as g: + g.write(data) + return f.getvalue() + + +def decompress(data): + f = io.BytesIO(data) + with GzipFile(fileobj=f) as g: + return g.read() diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/gzip.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/gzip.pyi new file mode 100644 index 000000000..d99c73d3c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/gzip.pyi @@ -0,0 +1,77 @@ +""" +Gzip compression & decompression. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/gzip.html + +CPython module: :mod:`python:gzip` https://docs.python.org/3/library/gzip.html . + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ used by the gzip +file format. + +``Note:`` Prefer to use :class:`deflate.DeflateIO` instead of the functions in this + module as it provides a streaming interface to compression and decompression + which is convenient and more memory efficient when working with reading or + writing compressed data to a file, socket, or stream. + +**Availability:** + +* This module is **not present by default** in official MicroPython firmware + releases as it duplicates functionality available in the :mod:`deflate + ` module. + +* A copy of this module can be installed (or frozen) + from :term:`micropython-lib` (`source `_). + See :ref:`packages` for more information. This documentation describes that module. + +* Compression support will only be available if compression support is enabled + in the built-in :mod:`deflate ` module. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_WBITS: int + +class GzipFile: + """ + This class can be used to wrap a *fileobj* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + When the *mode* argument is ``"rb"``, reads from the GzipFile instance will + decompress the data in the underlying stream and return decompressed data. + + If compression support is enabled then the *mode* argument can be set to + ``"wb"``, and writes to the GzipFile instance will be compressed and written + to the underlying stream. + + By default the GzipFile class will read and write data using the gzip file + format, including a header and footer with checksum and a window size of 512 + bytes. + + The **file**, **compresslevel**, and **mtime** arguments are not + supported. **fileobj** and **mode** must always be specified as keyword + arguments. + """ + def __init__(self, *, fileobj, mode) -> None: ... + +def open(filename, mode: str = "rb") -> Incomplete: + """ + Wrapper around built-in :func:`open` returning a GzipFile instance. + """ + ... + +def compress(data) -> Incomplete: + """ + Compresses *data* into a bytes object. + """ + ... + +def decompress(data) -> Incomplete: + """ + Decompresses *data* into a bytes object. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/hmac.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/hmac.py new file mode 100644 index 000000000..dbbdd4718 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/hmac.py @@ -0,0 +1,87 @@ +# Implements the hmac module from the Python standard library. + + +class HMAC: + def __init__(self, key, msg=None, digestmod=None): + if not isinstance(key, (bytes, bytearray)): + raise TypeError("key: expected bytes/bytearray") + + import hashlib + + if digestmod is None: + # TODO: Default hash algorithm is now deprecated. + digestmod = hashlib.md5 + + if callable(digestmod): + # A hashlib constructor returning a new hash object. + make_hash = digestmod # A + elif isinstance(digestmod, str): + # A hash name suitable for hashlib.new(). + make_hash = lambda d=b"": getattr(hashlib, digestmod)(d) + else: + # A module supporting PEP 247. + make_hash = digestmod.new # C + + self._outer = make_hash() + self._inner = make_hash() + + self.digest_size = getattr(self._inner, "digest_size", None) + # If the provided hash doesn't support block_size (e.g. built-in + # hashlib), 64 is the correct default for all built-in hash + # functions (md5, sha1, sha256). + self.block_size = getattr(self._inner, "block_size", 64) + + # Truncate to digest_size if greater than block_size. + if len(key) > self.block_size: + key = make_hash(key).digest() + + # Pad to block size. + key = key + bytes(self.block_size - len(key)) + + self._outer.update(bytes(x ^ 0x5C for x in key)) + self._inner.update(bytes(x ^ 0x36 for x in key)) + + if msg is not None: + self.update(msg) + + @property + def name(self): + return "hmac-" + getattr(self._inner, "name", type(self._inner).__name__) + + def update(self, msg): + self._inner.update(msg) + + def copy(self): + if not hasattr(self._inner, "copy"): + # Not supported for built-in hash functions. + raise NotImplementedError() + # Call __new__ directly to avoid the expensive __init__. + other = self.__class__.__new__(self.__class__) + other.block_size = self.block_size + other.digest_size = self.digest_size + other._inner = self._inner.copy() + other._outer = self._outer.copy() + return other + + def _current(self): + h = self._outer + if hasattr(h, "copy"): + # built-in hash functions don't support this, and as a result, + # digest() will finalise the hmac and further calls to + # update/digest will fail. + h = h.copy() + h.update(self._inner.digest()) + return h + + def digest(self): + h = self._current() + return h.digest() + + def hexdigest(self): + import binascii + + return str(binascii.hexlify(self.digest()), "utf-8") + + +def new(key, msg=None, digestmod=None): + return HMAC(key, msg, digestmod) diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/hmac.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/hmac.pyi new file mode 100644 index 000000000..c8c2d5e7f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/hmac.pyi @@ -0,0 +1,17 @@ +from _typeshed import Incomplete + +class HMAC: + _outer: Incomplete + _inner: Incomplete + digest_size: Incomplete + block_size: Incomplete + def __init__(self, key, msg=None, digestmod=None) -> None: ... + @property + def name(self): ... + def update(self, msg) -> None: ... + def copy(self): ... + def _current(self): ... + def digest(self): ... + def hexdigest(self): ... + +def new(key, msg=None, digestmod=None): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/html/__init__.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/html/__init__.py new file mode 100644 index 000000000..6fae53d1d --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/html/__init__.py @@ -0,0 +1,29 @@ +""" +General functions for HTML manipulation. +""" + + +_escape_map = {ord("&"): "&", ord("<"): "<", ord(">"): ">"} +_escape_map_full = { + ord("&"): "&", + ord("<"): "<", + ord(">"): ">", + ord('"'): """, + ord("'"): "'", +} + +# NB: this is a candidate for a bytes/string polymorphic interface + + +def escape(s, quote=True): + """ + Replace special characters "&", "<" and ">" to HTML-safe sequences. + If the optional flag quote is true (the default), the quotation mark + characters, both double quote (") and single quote (') characters are also + translated. + """ + import string + + if quote: + return string.translate(s, _escape_map_full) + return string.translate(s, _escape_map) diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/html/__init__.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/html/__init__.pyi new file mode 100644 index 000000000..6acdee9ce --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/html/__init__.pyi @@ -0,0 +1,12 @@ +from _typeshed import Incomplete + +_escape_map: Incomplete +_escape_map_full: Incomplete + +def escape(s, quote: bool = True): + ''' + Replace special characters "&", "<" and ">" to HTML-safe sequences. + If the optional flag quote is true (the default), the quotation mark + characters, both double quote (") and single quote (\') characters are also + translated. + ''' diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/inspect.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/inspect.py new file mode 100644 index 000000000..c16c6b3e3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/inspect.py @@ -0,0 +1,82 @@ +import sys + +_g = lambda: (yield) + + +def getmembers(obj, pred=None): + res = [] + for name in dir(obj): + val = getattr(obj, name) + if pred is None or pred(val): + res.append((name, val)) + res.sort() + return res + + +def isfunction(obj): + return isinstance(obj, type(isfunction)) + + +def isgeneratorfunction(obj): + return isinstance(obj, type(_g)) + + +def isgenerator(obj): + return isinstance(obj, type((_g)())) + + +# In MicroPython there's currently no way to distinguish between generators and coroutines. +iscoroutinefunction = isgeneratorfunction +iscoroutine = isgenerator + + +class _Class: + def meth(): + pass + + +_Instance = _Class() + + +def ismethod(obj): + return isinstance(obj, type(_Instance.meth)) + + +def isclass(obj): + return isinstance(obj, type) + + +def ismodule(obj): + return isinstance(obj, type(sys)) + + +def getargspec(func): + raise NotImplementedError("This is over-dynamic function, not supported by MicroPython") + + +def getmodule(obj, _filename=None): + return None # Not known + + +def getmro(cls): + return [cls] + + +def getsourcefile(obj): + return None # Not known + + +def getfile(obj): + return "" + + +def getsource(obj): + return "" + + +def currentframe(): + return None + + +def getframeinfo(frame, context=1): + return ("", -1, "", [""], 0) diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/inspect.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/inspect.pyi new file mode 100644 index 000000000..2cdbabe59 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/inspect.pyi @@ -0,0 +1,28 @@ +from _typeshed import Incomplete + +_g: Incomplete + +def getmembers(obj, pred=None): ... +def isfunction(obj): ... +def isgeneratorfunction(obj): ... +def isgenerator(obj): ... + +iscoroutinefunction = isgeneratorfunction +iscoroutine = isgenerator + +class _Class: + def meth() -> None: ... + +_Instance: Incomplete + +def ismethod(obj): ... +def isclass(obj): ... +def ismodule(obj): ... +def getargspec(func) -> None: ... +def getmodule(obj, _filename=None) -> None: ... +def getmro(cls): ... +def getsourcefile(obj) -> None: ... +def getfile(obj): ... +def getsource(obj): ... +def currentframe() -> None: ... +def getframeinfo(frame, context: int = 1): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/io.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/io.py new file mode 100644 index 000000000..adc29544b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/io.py @@ -0,0 +1,5 @@ +from uio import * + +SEEK_SET = 0 +SEEK_CUR = 1 +SEEK_END = 2 diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/io.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/io.pyi new file mode 100644 index 000000000..691c17a17 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/io.pyi @@ -0,0 +1,217 @@ +""" +Input/output streams. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/io.html + +CPython module: :mod:`python:io` https://docs.python.org/3/library/io.html . + +This module contains additional types of `stream` (file-like) objects +and helper functions. + +Conceptual hierarchy +-------------------- + +Admonition:Difference to CPython + :class: attention + + Conceptual hierarchy of stream base classes is simplified in MicroPython, + as described in this section. + +(Abstract) base stream classes, which serve as a foundation for behaviour +of all the concrete classes, adhere to few dichotomies (pair-wise +classifications) in CPython. In MicroPython, they are somewhat simplified +and made implicit to achieve higher efficiencies and save resources. + +An important dichotomy in CPython is unbuffered vs buffered streams. In +MicroPython, all streams are currently unbuffered. This is because all +modern OSes, and even many RTOSes and filesystem drivers already perform +buffering on their side. Adding another layer of buffering is counter- +productive (an issue known as "bufferbloat") and takes precious memory. +Note that there still cases where buffering may be useful, so we may +introduce optional buffering support at a later time. + +But in CPython, another important dichotomy is tied with "bufferedness" - +it's whether a stream may incur short read/writes or not. A short read +is when a user asks e.g. 10 bytes from a stream, but gets less, similarly +for writes. In CPython, unbuffered streams are automatically short +operation susceptible, while buffered are guarantee against them. The +no short read/writes is an important trait, as it allows to develop +more concise and efficient programs - something which is highly desirable +for MicroPython. So, while MicroPython doesn't support buffered streams, +it still provides for no-short-operations streams. Whether there will +be short operations or not depends on each particular class' needs, but +developers are strongly advised to favour no-short-operations behaviour +for the reasons stated above. For example, MicroPython sockets are +guaranteed to avoid short read/writes. Actually, at this time, there is +no example of a short-operations stream class in the core, and one would +be a port-specific class, where such a need is governed by hardware +peculiarities. + +The no-short-operations behaviour gets tricky in case of non-blocking +streams, blocking vs non-blocking behaviour being another CPython dichotomy, +fully supported by MicroPython. Non-blocking streams never wait for +data either to arrive or be written - they read/write whatever possible, +or signal lack of data (or ability to write data). Clearly, this conflicts +with "no-short-operations" policy, and indeed, a case of non-blocking +buffered (and this no-short-ops) streams is convoluted in CPython - in +some places, such combination is prohibited, in some it's undefined or +just not documented, in some cases it raises verbose exceptions. The +matter is much simpler in MicroPython: non-blocking stream are important +for efficient asynchronous operations, so this property prevails on +the "no-short-ops" one. So, while blocking streams will avoid short +reads/writes whenever possible (the only case to get a short read is +if end of file is reached, or in case of error (but errors don't +return short data, but raise exceptions)), non-blocking streams may +produce short data to avoid blocking the operation. + +The final dichotomy is binary vs text streams. MicroPython of course +supports these, but while in CPython text streams are inherently +buffered, they aren't in MicroPython. (Indeed, that's one of the cases +for which we may introduce buffering support.) + +Note that for efficiency, MicroPython doesn't provide abstract base +classes corresponding to the hierarchy above, and it's not possible +to implement, or subclass, a stream class in pure Python. +""" + +from __future__ import annotations +from uio import * +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, FileIO, IOBase_mp, PathLike, TextIOWrapper +from _mpy_shed.io_modes import _OpenBinaryMode, _OpenTextModeWriting +from _typeshed import Incomplete +from array import array +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +SEEK_SET: int +SEEK_CUR: int +SEEK_END: int +_T = TypeVar("_T") +AnyStr_co = TypeVar("AnyStr_co", str, bytes, covariant=True) +StrOrBytesPath = TypeVar("StrOrBytesPath", str, bytes, PathLike[str], PathLike[bytes]) +_OpenFile = TypeVar("_OpenFile", str, bytes, PathLike[str], PathLike[bytes], int) +AnyReadableBuf = TypeVar("AnyReadableBuf", bytearray, array, memoryview, bytes) +AnyWritableBuf = TypeVar("AnyWritableBuf", bytearray, array, memoryview) +_Self = TypeVar("_Self") + +class StringIO: + @overload + def __init__(self, string: str = "", /): + """ + + In-memory file-like object for input/output. + `StringIO` is used for text-mode I/O (similar to a normal file opened with "t" modifier). + Initial contents can be specified with `string` parameter. + + `alloc_size` constructor creates an empty `StringIO` object, + pre-allocated to hold up to `alloc_size` number of bytes. + That means that writing that amount of bytes won't lead to reallocation of the buffer, + and thus won't hit out-of-memory situation or lead to memory fragmentation. + This constructor is a MicroPython extension and is recommended for usage only in special + cases and in system-level libraries, not for end-user applications. + + .. admonition:: Difference to CPython + :class: attention + + This constructor is a MicroPython extension. + """ + + @overload + def __init__(self, alloc_size: int, /): + """ + + In-memory file-like object for input/output. + `StringIO` is used for text-mode I/O (similar to a normal file opened with "t" modifier). + Initial contents can be specified with `string` parameter. + + `alloc_size` constructor creates an empty `StringIO` object, + pre-allocated to hold up to `alloc_size` number of bytes. + That means that writing that amount of bytes won't lead to reallocation of the buffer, + and thus won't hit out-of-memory situation or lead to memory fragmentation. + This constructor is a MicroPython extension and is recommended for usage only in special + cases and in system-level libraries, not for end-user applications. + + .. admonition:: Difference to CPython + :class: attention + + This constructor is a MicroPython extension. + """ + +class BytesIO: + @overload + def __init__(self, string: bytes = b"", /): + """ + In-memory file-like objects for input/output. `StringIO` is used for + text-mode I/O (similar to a normal file opened with "t" modifier). + `BytesIO` is used for binary-mode I/O (similar to a normal file + opened with "b" modifier). Initial contents of file-like objects + can be specified with *string* parameter (should be normal string + for `StringIO` or bytes object for `BytesIO`). All the usual file + methods like ``read()``, ``write()``, ``seek()``, ``flush()``, + ``close()`` are available on these objects, and additionally, a + following method: + + + `alloc_size` constructor creates an empty `BytesIO` object, + pre-allocated to hold up to `alloc_size` number of bytes. + That means that writing that amount of bytes won't lead to reallocation of the buffer, + and thus won't hit out-of-memory situation or lead to memory fragmentation. + This constructor is a MicroPython extension and is recommended for usage only in special + cases and in system-level libraries, not for end-user applications. + + .. admonition:: Difference to CPython + :class: attention + + This constructor is a MicroPython extension. + """ + + @overload + def __init__(self, alloc_size: int, /): + """ + In-memory file-like objects for input/output. `StringIO` is used for + text-mode I/O (similar to a normal file opened with "t" modifier). + `BytesIO` is used for binary-mode I/O (similar to a normal file + opened with "b" modifier). Initial contents of file-like objects + can be specified with *string* parameter (should be normal string + for `StringIO` or bytes object for `BytesIO`). All the usual file + methods like ``read()``, ``write()``, ``seek()``, ``flush()``, + ``close()`` are available on these objects, and additionally, a + following method: + + + `alloc_size` constructor creates an empty `BytesIO` object, + pre-allocated to hold up to `alloc_size` number of bytes. + That means that writing that amount of bytes won't lead to reallocation of the buffer, + and thus won't hit out-of-memory situation or lead to memory fragmentation. + This constructor is a MicroPython extension and is recommended for usage only in special + cases and in system-level libraries, not for end-user applications. + + .. admonition:: Difference to CPython + :class: attention + + This constructor is a MicroPython extension. + """ + +@overload +def open(name: _OpenFile, /, **kwargs) -> TextIOWrapper: + """ + Open a file. Builtin ``open()`` function is aliased to this function. + All ports (which provide access to file system) are required to support + *mode* parameter, but support for other arguments vary by port. + """ + +@overload +def open(name: _OpenFile, mode: _OpenTextModeWriting = ..., /, **kwargs) -> TextIOWrapper: + """ + Open a file. Builtin ``open()`` function is aliased to this function. + All ports (which provide access to file system) are required to support + *mode* parameter, but support for other arguments vary by port. + """ + +@overload +def open(name: _OpenFile, mode: _OpenBinaryMode = ..., /, **kwargs) -> FileIO: + """ + Open a file. Builtin ``open()`` function is aliased to this function. + All ports (which provide access to file system) are required to support + *mode* parameter, but support for other arguments vary by port. + """ diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/itertools.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/itertools.py new file mode 100644 index 000000000..9bf1b2158 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/itertools.py @@ -0,0 +1,74 @@ +def count(start=0, step=1): + while True: + yield start + start += step + + +def cycle(p): + try: + len(p) + except TypeError: + # len() is not defined for this type. Assume it is + # a finite iterable so we must cache the elements. + cache = [] + for i in p: + yield i + cache.append(i) + p = cache + while p: + yield from p + + +def repeat(el, n=None): + if n is None: + while True: + yield el + else: + for i in range(n): + yield el + + +def chain(*p): + for i in p: + yield from i + + +def islice(p, start, stop=(), step=1): + if stop == (): + stop = start + start = 0 + # TODO: optimizing or breaking semantics? + if start >= stop: + return + it = iter(p) + for i in range(start): + next(it) + + while True: + yield next(it) + for i in range(step - 1): + next(it) + start += step + if start >= stop: + return + + +def tee(iterable, n=2): + return [iter(iterable)] * n + + +def starmap(function, iterable): + for args in iterable: + yield function(*args) + + +def accumulate(iterable, func=lambda x, y: x + y): + it = iter(iterable) + try: + acc = next(it) + except StopIteration: + return + yield acc + for element in it: + acc = func(acc, element) + yield acc diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/itertools.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/itertools.pyi new file mode 100644 index 000000000..ad7f80af3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/itertools.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete +from collections.abc import Generator + +def count(start: int = 0, step: int = 1) -> Generator[Incomplete]: ... +def cycle(p) -> Generator[Incomplete, Incomplete]: ... +def repeat(el, n=None) -> Generator[Incomplete]: ... +def chain(*p) -> Generator[Incomplete, Incomplete]: ... +def islice(p, start, stop=(), step: int = 1) -> Generator[Incomplete]: ... +def tee(iterable, n: int = 2): ... +def starmap(function, iterable) -> Generator[Incomplete]: ... +def accumulate(iterable, func=...) -> Generator[Incomplete, None, Incomplete]: ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/locale.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/locale.py new file mode 100644 index 000000000..a047b65ee --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/locale.py @@ -0,0 +1,2 @@ +def getpreferredencoding(): + return "utf-8" diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/locale.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/locale.pyi new file mode 100644 index 000000000..b5f532434 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/locale.pyi @@ -0,0 +1 @@ +def getpreferredencoding(): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/logging.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/logging.py new file mode 100644 index 000000000..edee407c6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/logging.py @@ -0,0 +1,253 @@ +from micropython import const +import io +import sys +import time + +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 + +_DEFAULT_LEVEL = WARNING + +_level_dict = { + CRITICAL: "CRITICAL", + ERROR: "ERROR", + WARNING: "WARNING", + INFO: "INFO", + DEBUG: "DEBUG", + NOTSET: "NOTSET", +} + +_loggers = {} +_stream = sys.stderr +_default_fmt = "%(levelname)s:%(name)s:%(message)s" +_default_datefmt = "%Y-%m-%d %H:%M:%S" + + +class LogRecord: + def set(self, name, level, message): + self.name = name + self.levelno = level + self.levelname = _level_dict[level] + self.message = message + self.ct = time.time() + self.msecs = int((self.ct - int(self.ct)) * 1000) + self.asctime = None + + +class Handler: + def __init__(self, level=NOTSET): + self.level = level + self.formatter = None + + def close(self): + pass + + def setLevel(self, level): + self.level = level + + def setFormatter(self, formatter): + self.formatter = formatter + + def format(self, record): + return self.formatter.format(record) + + +class StreamHandler(Handler): + def __init__(self, stream=None): + super().__init__() + self.stream = _stream if stream is None else stream + self.terminator = "\n" + + def close(self): + if hasattr(self.stream, "flush"): + self.stream.flush() + + def emit(self, record): + if record.levelno >= self.level: + self.stream.write(self.format(record) + self.terminator) + + +class FileHandler(StreamHandler): + def __init__(self, filename, mode="a", encoding="UTF-8"): + super().__init__(stream=open(filename, mode=mode, encoding=encoding)) + + def close(self): + super().close() + self.stream.close() + + +class Formatter: + def __init__(self, fmt=None, datefmt=None): + self.fmt = _default_fmt if fmt is None else fmt + self.datefmt = _default_datefmt if datefmt is None else datefmt + + def usesTime(self): + return "asctime" in self.fmt + + def formatTime(self, datefmt, record): + if hasattr(time, "strftime"): + return time.strftime(datefmt, time.localtime(record.ct)) + return None + + def format(self, record): + if self.usesTime(): + record.asctime = self.formatTime(self.datefmt, record) + return self.fmt % { + "name": record.name, + "message": record.message, + "msecs": record.msecs, + "asctime": record.asctime, + "levelname": record.levelname, + } + + +class Logger: + def __init__(self, name, level=NOTSET): + self.name = name + self.level = level + self.handlers = [] + self.record = LogRecord() + + def setLevel(self, level): + self.level = level + + def isEnabledFor(self, level): + return level >= self.getEffectiveLevel() + + def getEffectiveLevel(self): + return self.level or getLogger().level or _DEFAULT_LEVEL + + def log(self, level, msg, *args): + if self.isEnabledFor(level): + if args: + if isinstance(args[0], dict): + args = args[0] + msg = msg % args + self.record.set(self.name, level, msg) + handlers = self.handlers + if not handlers: + handlers = getLogger().handlers + for h in handlers: + h.emit(self.record) + + def debug(self, msg, *args): + self.log(DEBUG, msg, *args) + + def info(self, msg, *args): + self.log(INFO, msg, *args) + + def warning(self, msg, *args): + self.log(WARNING, msg, *args) + + def error(self, msg, *args): + self.log(ERROR, msg, *args) + + def critical(self, msg, *args): + self.log(CRITICAL, msg, *args) + + def exception(self, msg, *args, exc_info=True): + self.log(ERROR, msg, *args) + tb = None + if isinstance(exc_info, BaseException): + tb = exc_info + elif hasattr(sys, "exc_info"): + tb = sys.exc_info()[1] + if tb: + buf = io.StringIO() + sys.print_exception(tb, buf) + self.log(ERROR, buf.getvalue()) + + def addHandler(self, handler): + self.handlers.append(handler) + + def hasHandlers(self): + return len(self.handlers) > 0 + + +def getLogger(name=None): + if name is None: + name = "root" + if name not in _loggers: + _loggers[name] = Logger(name) + if name == "root": + basicConfig() + return _loggers[name] + + +def log(level, msg, *args): + getLogger().log(level, msg, *args) + + +def debug(msg, *args): + getLogger().debug(msg, *args) + + +def info(msg, *args): + getLogger().info(msg, *args) + + +def warning(msg, *args): + getLogger().warning(msg, *args) + + +def error(msg, *args): + getLogger().error(msg, *args) + + +def critical(msg, *args): + getLogger().critical(msg, *args) + + +def exception(msg, *args, exc_info=True): + getLogger().exception(msg, *args, exc_info=exc_info) + + +def shutdown(): + for k, logger in _loggers.items(): + for h in logger.handlers: + h.close() + _loggers.pop(logger, None) + + +def addLevelName(level, name): + _level_dict[level] = name + + +def basicConfig( + filename=None, + filemode="a", + format=None, + datefmt=None, + level=WARNING, + stream=None, + encoding="UTF-8", + force=False, +): + if "root" not in _loggers: + _loggers["root"] = Logger("root") + + logger = _loggers["root"] + + if force or not logger.handlers: + for h in logger.handlers: + h.close() + logger.handlers = [] + + if filename is None: + handler = StreamHandler(stream) + else: + handler = FileHandler(filename, filemode, encoding) + + handler.setLevel(level) + handler.setFormatter(Formatter(format, datefmt)) + + logger.setLevel(level) + logger.addHandler(handler) + + +if hasattr(sys, "atexit"): + sys.atexit(shutdown) diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/logging.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/logging.pyi new file mode 100644 index 000000000..856bcccf7 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/logging.pyi @@ -0,0 +1,86 @@ +from _typeshed import Incomplete +from micropython import const as const + +CRITICAL: int +ERROR: int +WARNING: int +INFO: int +DEBUG: int +NOTSET: int +_DEFAULT_LEVEL = WARNING +_level_dict: Incomplete +_loggers: Incomplete +_stream: Incomplete +_default_fmt: str +_default_datefmt: str + +class LogRecord: + name: Incomplete + levelno: Incomplete + levelname: Incomplete + message: Incomplete + ct: Incomplete + msecs: Incomplete + asctime: Incomplete + def set(self, name, level, message) -> None: ... + +class Handler: + level: Incomplete + formatter: Incomplete + def __init__(self, level=...) -> None: ... + def close(self) -> None: ... + def setLevel(self, level) -> None: ... + def setFormatter(self, formatter) -> None: ... + def format(self, record): ... + +class StreamHandler(Handler): + stream: Incomplete + terminator: str + def __init__(self, stream=None) -> None: ... + def close(self) -> None: ... + def emit(self, record) -> None: ... + +class FileHandler(StreamHandler): + def __init__(self, filename, mode: str = "a", encoding: str = "UTF-8") -> None: ... + def close(self) -> None: ... + +class Formatter: + fmt: Incomplete + datefmt: Incomplete + def __init__(self, fmt=None, datefmt=None) -> None: ... + def usesTime(self): ... + def formatTime(self, datefmt, record): ... + def format(self, record): ... + +class Logger: + name: Incomplete + level: Incomplete + handlers: Incomplete + record: Incomplete + def __init__(self, name, level=...) -> None: ... + def setLevel(self, level) -> None: ... + def isEnabledFor(self, level): ... + def getEffectiveLevel(self): ... + def log(self, level, msg, *args) -> None: ... + def debug(self, msg, *args) -> None: ... + def info(self, msg, *args) -> None: ... + def warning(self, msg, *args) -> None: ... + def error(self, msg, *args) -> None: ... + def critical(self, msg, *args) -> None: ... + def exception(self, msg, *args, exc_info: bool = True) -> None: ... + def addHandler(self, handler) -> None: ... + def hasHandlers(self): ... + +def getLogger(name=None): ... +def log(level, msg, *args) -> None: ... +def debug(msg, *args) -> None: ... +def info(msg, *args) -> None: ... +def warning(msg, *args) -> None: ... +def error(msg, *args) -> None: ... +def critical(msg, *args) -> None: ... +def exception(msg, *args, exc_info: bool = True) -> None: ... +def shutdown() -> None: ... +def addLevelName(level, name) -> None: ... +def basicConfig( + filename=None, filemode: str = "a", format=None, datefmt=None, level=..., stream=None, encoding: str = "UTF-8", force: bool = False +) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/modules.json new file mode 100644 index 000000000..c32cb4b11 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/modules.json @@ -0,0 +1,140 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "webassembly", + "platform": "webassembly", + "machine": "GENERIC", + "firmware": "micropython-webassembly-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "abc.py", + "module": "abc" + }, + { + "file": "base64.py", + "module": "base64" + }, + { + "file": "binascii.py", + "module": "binascii" + }, + { + "file": "collections/__init__.py", + "module": "__init__" + }, + { + "file": "collections/defaultdict.py", + "module": "defaultdict" + }, + { + "file": "copy.py", + "module": "copy" + }, + { + "file": "datetime.py", + "module": "datetime" + }, + { + "file": "fnmatch.py", + "module": "fnmatch" + }, + { + "file": "functools.py", + "module": "functools" + }, + { + "file": "gzip.py", + "module": "gzip" + }, + { + "file": "hmac.py", + "module": "hmac" + }, + { + "file": "html/__init__.py", + "module": "__init__" + }, + { + "file": "inspect.py", + "module": "inspect" + }, + { + "file": "io.py", + "module": "io" + }, + { + "file": "itertools.py", + "module": "itertools" + }, + { + "file": "locale.py", + "module": "locale" + }, + { + "file": "logging.py", + "module": "logging" + }, + { + "file": "operator.py", + "module": "operator" + }, + { + "file": "os/__init__.py", + "module": "__init__" + }, + { + "file": "os/path.py", + "module": "path" + }, + { + "file": "pathlib.py", + "module": "pathlib" + }, + { + "file": "stat.py", + "module": "stat" + }, + { + "file": "string.py", + "module": "string" + }, + { + "file": "tarfile/__init__.py", + "module": "__init__" + }, + { + "file": "tarfile/write.py", + "module": "write" + }, + { + "file": "time.py", + "module": "time" + }, + { + "file": "types.py", + "module": "types" + }, + { + "file": "unittest/__init__.py", + "module": "__init__" + }, + { + "file": "uu.py", + "module": "uu" + }, + { + "file": "zlib.py", + "module": "zlib" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/operator.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/operator.py new file mode 100644 index 000000000..e20987395 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/operator.py @@ -0,0 +1,43 @@ +def attrgetter(attr): + assert "." not in attr + + def _attrgetter(obj): + return getattr(obj, attr) + + return _attrgetter + + +def lt(a, b): + return a < b + + +def le(a, b): + return a <= b + + +def gt(a, b): + return a > b + + +def ge(a, b): + return a >= b + + +def eq(a, b): + return a == b + + +def ne(a, b): + return a != b + + +def mod(a, b): + return a % b + + +def truediv(a, b): + return a / b + + +def floordiv(a, b): + return a // b diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/operator.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/operator.pyi new file mode 100644 index 000000000..d0cc0258a --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/operator.pyi @@ -0,0 +1,10 @@ +def attrgetter(attr): ... +def lt(a, b): ... +def le(a, b): ... +def gt(a, b): ... +def ge(a, b): ... +def eq(a, b): ... +def ne(a, b): ... +def mod(a, b): ... +def truediv(a, b): ... +def floordiv(a, b): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/__init__.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/__init__.py new file mode 100644 index 000000000..6e51bd0d3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/__init__.py @@ -0,0 +1,8 @@ +# Replace built-in os module. +from uos import * + +# Provide optional dependencies (which may be installed separately). +try: + from . import path +except ImportError: + pass diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/__init__.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/__init__.pyi new file mode 100644 index 000000000..d9689fa76 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/__init__.pyi @@ -0,0 +1,211 @@ +""" +Basic "operating system" services. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/os.html + +CPython module: :mod:`python:os` https://docs.python.org/3/library/os.html . + +The ``os`` module contains functions for filesystem access and mounting, +terminal redirection and duplication, and the ``uname`` and ``urandom`` +functions. +""" +from __future__ import annotations +from uos import * +from . import path as path +from _mpy_shed import mp_available, uname_result +from _typeshed import Incomplete +from typing import Any, IO, Iterator, Optional, Tuple, Union, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated + +@overload +def ilistdir(dir: Union[str,bytes]) -> Iterator[Union[Tuple[str, int, int], Tuple[str, int, int, int]]]: + """ + This function returns an iterator which then yields tuples corresponding to + the entries in the directory that it is listing. With no argument it lists the + current directory, otherwise it lists the directory given by *dir*. + + The tuples have the form *(name, type, inode[, size])*: + + - *name* is a string (or bytes if *dir* is a bytes object) and is the name of + the entry; + - *type* is an integer that specifies the type of the entry, with 0x4000 for + directories and 0x8000 for regular files; + - *inode* is an integer corresponding to the inode of the file, and may be 0 + for filesystems that don't have such a notion. + - Some platforms may return a 4-tuple that includes the entry's *size*. For + file entries, *size* is an integer representing the size of the file + or -1 if unknown. Its meaning is currently undefined for directory + entries. + """ + ... +@overload +def ilistdir() -> Iterator[Union[Tuple[str, int, int], Tuple[str, int, int, int]]]: ... + +@mp_available() # force merge +def urandom(n:int) -> bytes: + """ + Return a bytes object with *n* random bytes. Whenever possible, it is + generated by the hardware random number generator. + """ + ... + +@mp_available() # force merge +def chdir(path) -> Incomplete: + """ + Change current directory. + """ + ... + +@mp_available() # force merge +def getcwd() -> Incomplete: + """ + Get the current directory. + """ + ... + + + +@mp_available() # force merge +def listdir(dir: Optional[Any] = None) -> Incomplete: + """ + With no argument, list the current directory. Otherwise list the given directory. + """ + ... + +@mp_available() # force merge +def mkdir(path) -> Incomplete: + """ + Create a new directory. + """ + ... + +@mp_available() # force merge +def remove(path) -> None: + """ + Remove a file. + """ + ... + +@mp_available() # force merge +def rmdir(path) -> None: + """ + Remove a directory. + """ + ... + +@mp_available() # force merge +def rename(old_path, new_path) -> None: + """ + Rename a file. + """ + ... + +@mp_available() # force merge +def statvfs(path) -> Tuple: + """ + 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. + """ + ... + +@mp_available() # force merge +def sync() -> None: + """ + Sync all filesystems. + """ + ... + +@mp_available() # force merge +def dupterm(stream_object, index=0, /) -> IO: + """ + Duplicate or switch the MicroPython terminal (the REPL) on the given `stream`-like + object. The *stream_object* argument must be a native stream object, or derive + from ``io.IOBase`` and implement the ``readinto()`` and + ``write()`` methods. The stream should be in non-blocking mode and + ``readinto()`` should return ``None`` if there is no data available for reading. + + After calling this function all terminal output is repeated on this stream, + and any input that is available on the stream is passed on to the terminal input. + + The *index* parameter should be a non-negative integer and specifies which + duplication slot is set. A given port may implement more than one slot (slot 0 + will always be available) and in that case terminal input and output is + duplicated on all the slots that are set. + + If ``None`` is passed as the *stream_object* then duplication is cancelled on + the slot given by *index*. + + The function returns the previous stream-like object in the given slot. + """ + ... + + +# Deprecated functions and classes +# The following functions and classes have been moved to the vfs module. + +@mp_available() # force merge +@deprecated( "The `mount` function is deprecated, use `vfs.mount` instead.") +def mount(fsobj, mount_point, *, readonly=False) -> Incomplete: + """ + See `vfs.mount`. + """ + ... + +@mp_available() # force merge +@deprecated( "The `umount` function is deprecated, use `vfs.umount` instead.") +def umount(mount_point) -> Incomplete: + """ + See `vfs.umount`. + """ + ... + +@mp_available() # force merge +def dupterm_notify(obj_in: Any, /) -> None: + # https://github.com/orgs/micropython/discussions/16680 + # https://github.com/micropython/micropython/issues/17799 + """ + Notify the MicroPython REPL that input is available on a stream-like object + previously registered via `os.dupterm()`. + + This function should be called by custom stream implementations (e.g., UART, + Bluetooth, or other non-USB REPL streams) to inform the REPL that input is + ready to be read. Proper use ensures that special characters such as + Ctrl+C (used to trigger KeyboardInterrupt) are processed promptly by the + REPL, enabling expected interruption behavior for user code. + + Args: + obj_in: Is ignored by dupterm_notify, but is required to allow calling + dupterm_notify from an interrupt handler such as UART.irq() + Note: + - If input is available (including control characters like Ctrl+C), + call this function to ensure responsive REPL behavior. + - If omitted, input from the custom stream may not be detected or + processed until the next REPL poll, potentially delaying KeyboardInterrupts + or other control signals. + - This is especially important for UART, Bluetooth, or other + non-standard REPL connections, where automatic notification is not guaranteed. + + Example: + from machine import UART + import os + uart = UART(0) + uart.irq(os.dupterm_notify, machine.UART.IRQ_RX) # or UART.IRQ_RXIDLE + os.dupterm(uart, 0) + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/path.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/path.py new file mode 100644 index 000000000..b9ae1972f --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/path.py @@ -0,0 +1,83 @@ +import os + + +sep = "/" + + +def normcase(s): + return s + + +def normpath(s): + return s + + +def abspath(s): + if s[0] != "/": + return os.getcwd() + "/" + s + return s + + +def join(*args): + # TODO: this is non-compliant + if type(args[0]) is bytes: + return b"/".join(args) + else: + return "/".join(args) + + +def split(path): + if path == "": + return ("", "") + r = path.rsplit("/", 1) + if len(r) == 1: + return ("", path) + head = r[0] # .rstrip("/") + if not head: + head = "/" + return (head, r[1]) + + +def dirname(path): + return split(path)[0] + + +def basename(path): + return split(path)[1] + + +def exists(path): + try: + os.stat(path) + return True + except OSError: + return False + + +# TODO +lexists = exists + + +def isdir(path): + try: + mode = os.stat(path)[0] + return mode & 0o040000 + except OSError: + return False + + +def isfile(path): + try: + return bool(os.stat(path)[0] & 0x8000) + except OSError: + return False + + +def expanduser(s): + if s == "~" or s.startswith("~/"): + h = os.getenv("HOME") + return h + s[1:] + if s[0] == "~": + # Sorry folks, follow conventions + return "/home/" + s[1:] + return s diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/path.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/path.pyi new file mode 100644 index 000000000..e335411e6 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/os/path.pyi @@ -0,0 +1,16 @@ +sep: str + +def normcase(s): ... +def normpath(s): ... +def abspath(s): ... +def join(*args): ... +def split(path): ... +def dirname(path): ... +def basename(path): ... +def exists(path): ... + +lexists = exists + +def isdir(path): ... +def isfile(path): ... +def expanduser(s): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/pathlib.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/pathlib.py new file mode 100644 index 000000000..3bbea9518 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/pathlib.py @@ -0,0 +1,210 @@ +import errno +import os + +from micropython import const + +_SEP = "/" + + +def _mode_if_exists(path): + try: + return os.stat(path)[0] + except OSError as e: + if e.errno == errno.ENOENT: + return 0 + raise e + + +def _clean_segment(segment): + segment = str(segment) + if not segment: + return "." + segment = segment.rstrip(_SEP) + if not segment: + return _SEP + while True: + no_double = segment.replace(_SEP + _SEP, _SEP) + if no_double == segment: + break + segment = no_double + return segment + + +class Path: + def __init__(self, *segments): + segments_cleaned = [] + for segment in segments: + segment = _clean_segment(segment) + if segment[0] == _SEP: + segments_cleaned = [segment] + elif segment == ".": + continue + else: + segments_cleaned.append(segment) + + self._path = _clean_segment(_SEP.join(segments_cleaned)) + + def __truediv__(self, other): + return Path(self._path, str(other)) + + def __rtruediv__(self, other): + return Path(other, self._path) + + def __repr__(self): + return f'{type(self).__name__}("{self._path}")' + + def __str__(self): + return self._path + + def __eq__(self, other): + return self.absolute() == Path(other).absolute() + + def absolute(self): + path = self._path + cwd = os.getcwd() + if not path or path == ".": + return cwd + if path[0] == _SEP: + return path + return _SEP + path if cwd == _SEP else cwd + _SEP + path + + def resolve(self): + return self.absolute() + + def open(self, mode="r", encoding=None): + return open(self._path, mode, encoding=encoding) + + def exists(self): + return bool(_mode_if_exists(self._path)) + + def mkdir(self, parents=False, exist_ok=False): + try: + os.mkdir(self._path) + return + except OSError as e: + if e.errno == errno.EEXIST and exist_ok: + return + elif e.errno == errno.ENOENT and parents: + pass # handled below + else: + raise e + + segments = self._path.split(_SEP) + progressive_path = "" + if segments[0] == "": + segments = segments[1:] + progressive_path = _SEP + for segment in segments: + progressive_path += _SEP + segment + try: + os.mkdir(progressive_path) + except OSError as e: + if e.errno != errno.EEXIST: + raise e + + def is_dir(self): + return bool(_mode_if_exists(self._path) & 0x4000) + + def is_file(self): + return bool(_mode_if_exists(self._path) & 0x8000) + + def _glob(self, path, pattern, recursive): + # Currently only supports a single "*" pattern. + n_wildcards = pattern.count("*") + n_single_wildcards = pattern.count("?") + + if n_single_wildcards: + raise NotImplementedError("? single wildcards not implemented.") + + if n_wildcards == 0: + raise ValueError + elif n_wildcards > 1: + raise NotImplementedError("Multiple * wildcards not implemented.") + + prefix, suffix = pattern.split("*") + + for name, mode, *_ in os.ilistdir(path): + full_path = path + _SEP + name + if name.startswith(prefix) and name.endswith(suffix): + yield full_path + if recursive and mode & 0x4000: # is_dir + yield from self._glob(full_path, pattern, recursive=recursive) + + def glob(self, pattern): + """Iterate over this subtree and yield all existing files (of any + kind, including directories) matching the given relative pattern. + + Currently only supports a single "*" pattern. + """ + return self._glob(self._path, pattern, recursive=False) + + def rglob(self, pattern): + return self._glob(self._path, pattern, recursive=True) + + def stat(self): + return os.stat(self._path) + + def read_bytes(self): + with open(self._path, "rb") as f: + return f.read() + + def read_text(self, encoding=None): + with open(self._path, "r", encoding=encoding) as f: + return f.read() + + def rename(self, target): + os.rename(self._path, target) + + def rmdir(self): + os.rmdir(self._path) + + def touch(self, exist_ok=True): + if self.exists(): + if exist_ok: + return # TODO: should update timestamp + else: + # In lieue of FileExistsError + raise OSError(errno.EEXIST) + with open(self._path, "w"): + pass + + def unlink(self, missing_ok=False): + try: + os.unlink(self._path) + except OSError as e: + if not (missing_ok and e.errno == errno.ENOENT): + raise e + + def write_bytes(self, data): + with open(self._path, "wb") as f: + f.write(data) + + def write_text(self, data, encoding=None): + with open(self._path, "w", encoding=encoding) as f: + f.write(data) + + def with_suffix(self, suffix): + index = -len(self.suffix) or None + return Path(self._path[:index] + suffix) + + @property + def stem(self): + return self.name.rsplit(".", 1)[0] + + @property + def parent(self): + tokens = self._path.rsplit(_SEP, 1) + if len(tokens) == 2: + if not tokens[0]: + tokens[0] = _SEP + return Path(tokens[0]) + return Path(".") + + @property + def name(self): + return self._path.rsplit(_SEP, 1)[-1] + + @property + def suffix(self): + elems = self._path.rsplit(".", 1) + return "" if len(elems) == 1 else "." + elems[1] diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/pathlib.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/pathlib.pyi new file mode 100644 index 000000000..c5477b8a4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/pathlib.pyi @@ -0,0 +1,50 @@ +from _typeshed import Incomplete +from collections.abc import Generator +from micropython import const as const + +_SEP: str + +def _mode_if_exists(path): ... +def _clean_segment(segment): ... + +class Path: + _path: Incomplete + def __init__(self, *segments) -> None: ... + def __truediv__(self, other): ... + def __rtruediv__(self, other): ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... + def __eq__(self, other): ... + def absolute(self): ... + def resolve(self): ... + def open(self, mode: str = "r", encoding=None): ... + def exists(self): ... + def mkdir(self, parents: bool = False, exist_ok: bool = False) -> None: ... + def is_dir(self): ... + def is_file(self): ... + def _glob(self, path, pattern, recursive) -> Generator[Incomplete, Incomplete]: ... + def glob(self, pattern): + """Iterate over this subtree and yield all existing files (of any + kind, including directories) matching the given relative pattern. + + Currently only supports a single "*" pattern. + """ + def rglob(self, pattern): ... + def stat(self): ... + def read_bytes(self): ... + def read_text(self, encoding=None): ... + def rename(self, target) -> None: ... + def rmdir(self) -> None: ... + def touch(self, exist_ok: bool = True) -> None: ... + def unlink(self, missing_ok: bool = False) -> None: ... + def write_bytes(self, data) -> None: ... + def write_text(self, data, encoding=None) -> None: ... + def with_suffix(self, suffix): ... + @property + def stem(self): ... + @property + def parent(self): ... + @property + def name(self): ... + @property + def suffix(self): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/stat.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/stat.py new file mode 100644 index 000000000..f5ebea8f4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/stat.py @@ -0,0 +1,154 @@ +"""Constants/functions for interpreting results of os.stat() and os.lstat(). + +Suggested usage: from stat import * +""" + +# Indices for stat struct members in the tuple returned by os.stat() + +ST_MODE = 0 +ST_INO = 1 +ST_DEV = 2 +ST_NLINK = 3 +ST_UID = 4 +ST_GID = 5 +ST_SIZE = 6 +ST_ATIME = 7 +ST_MTIME = 8 +ST_CTIME = 9 + +# Extract bits from the mode + + +def S_IMODE(mode): + """Return the portion of the file's mode that can be set by + os.chmod(). + """ + return mode & 0o7777 + + +def S_IFMT(mode): + """Return the portion of the file's mode that describes the + file type. + """ + return mode & 0o170000 + + +# Constants used as S_IFMT() for various file types +# (not all are implemented on all systems) + +S_IFDIR = 0o040000 # directory +S_IFCHR = 0o020000 # character device +S_IFBLK = 0o060000 # block device +S_IFREG = 0o100000 # regular file +S_IFIFO = 0o010000 # fifo (named pipe) +S_IFLNK = 0o120000 # symbolic link +S_IFSOCK = 0o140000 # socket file + +# Functions to test for each file type + + +def S_ISDIR(mode): + """Return True if mode is from a directory.""" + return S_IFMT(mode) == S_IFDIR + + +def S_ISCHR(mode): + """Return True if mode is from a character special device file.""" + return S_IFMT(mode) == S_IFCHR + + +def S_ISBLK(mode): + """Return True if mode is from a block special device file.""" + return S_IFMT(mode) == S_IFBLK + + +def S_ISREG(mode): + """Return True if mode is from a regular file.""" + return S_IFMT(mode) == S_IFREG + + +def S_ISFIFO(mode): + """Return True if mode is from a FIFO (named pipe).""" + return S_IFMT(mode) == S_IFIFO + + +def S_ISLNK(mode): + """Return True if mode is from a symbolic link.""" + return S_IFMT(mode) == S_IFLNK + + +def S_ISSOCK(mode): + """Return True if mode is from a socket.""" + return S_IFMT(mode) == S_IFSOCK + + +# Names for permission bits + +S_ISUID = 0o4000 # set UID bit +S_ISGID = 0o2000 # set GID bit +S_ENFMT = S_ISGID # file locking enforcement +S_ISVTX = 0o1000 # sticky bit +S_IREAD = 0o0400 # Unix V7 synonym for S_IRUSR +S_IWRITE = 0o0200 # Unix V7 synonym for S_IWUSR +S_IEXEC = 0o0100 # Unix V7 synonym for S_IXUSR +S_IRWXU = 0o0700 # mask for owner permissions +S_IRUSR = 0o0400 # read by owner +S_IWUSR = 0o0200 # write by owner +S_IXUSR = 0o0100 # execute by owner +S_IRWXG = 0o0070 # mask for group permissions +S_IRGRP = 0o0040 # read by group +S_IWGRP = 0o0020 # write by group +S_IXGRP = 0o0010 # execute by group +S_IRWXO = 0o0007 # mask for others (not in group) permissions +S_IROTH = 0o0004 # read by others +S_IWOTH = 0o0002 # write by others +S_IXOTH = 0o0001 # execute by others + +# Names for file flags + +UF_NODUMP = 0x00000001 # do not dump file +UF_IMMUTABLE = 0x00000002 # file may not be changed +UF_APPEND = 0x00000004 # file may only be appended to +UF_OPAQUE = 0x00000008 # directory is opaque when viewed through a union stack +UF_NOUNLINK = 0x00000010 # file may not be renamed or deleted +UF_COMPRESSED = 0x00000020 # OS X: file is hfs-compressed +UF_HIDDEN = 0x00008000 # OS X: file should not be displayed +SF_ARCHIVED = 0x00010000 # file may be archived +SF_IMMUTABLE = 0x00020000 # file may not be changed +SF_APPEND = 0x00040000 # file may only be appended to +SF_NOUNLINK = 0x00100000 # file may not be renamed or deleted +SF_SNAPSHOT = 0x00200000 # file is a snapshot file + + +_filemode_table = ( + ( + (S_IFLNK, "l"), + (S_IFREG, "-"), + (S_IFBLK, "b"), + (S_IFDIR, "d"), + (S_IFCHR, "c"), + (S_IFIFO, "p"), + ), + ((S_IRUSR, "r"),), + ((S_IWUSR, "w"),), + ((S_IXUSR | S_ISUID, "s"), (S_ISUID, "S"), (S_IXUSR, "x")), + ((S_IRGRP, "r"),), + ((S_IWGRP, "w"),), + ((S_IXGRP | S_ISGID, "s"), (S_ISGID, "S"), (S_IXGRP, "x")), + ((S_IROTH, "r"),), + ((S_IWOTH, "w"),), + ((S_IXOTH | S_ISVTX, "t"), (S_ISVTX, "T"), (S_IXOTH, "x")), +) + + +def filemode(mode): + """Convert a file's mode to a string of the form '-rwxrwxrwx'.""" + perm = [] + for table in _filemode_table: + for bit, char in table: + if mode & bit == bit: + perm.append(char) + break + else: + perm.append("-") + return "".join(perm) diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/stat.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/stat.pyi new file mode 100644 index 000000000..73821fb06 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/stat.pyi @@ -0,0 +1,87 @@ +from _typeshed import Incomplete + +ST_MODE: int +ST_INO: int +ST_DEV: int +ST_NLINK: int +ST_UID: int +ST_GID: int +ST_SIZE: int +ST_ATIME: int +ST_MTIME: int +ST_CTIME: int + +def S_IMODE(mode): + """Return the portion of the file's mode that can be set by + os.chmod(). + """ + +def S_IFMT(mode): + """Return the portion of the file's mode that describes the + file type. + """ + +S_IFDIR: int +S_IFCHR: int +S_IFBLK: int +S_IFREG: int +S_IFIFO: int +S_IFLNK: int +S_IFSOCK: int + +def S_ISDIR(mode): + """Return True if mode is from a directory.""" + +def S_ISCHR(mode): + """Return True if mode is from a character special device file.""" + +def S_ISBLK(mode): + """Return True if mode is from a block special device file.""" + +def S_ISREG(mode): + """Return True if mode is from a regular file.""" + +def S_ISFIFO(mode): + """Return True if mode is from a FIFO (named pipe).""" + +def S_ISLNK(mode): + """Return True if mode is from a symbolic link.""" + +def S_ISSOCK(mode): + """Return True if mode is from a socket.""" + +S_ISUID: int +S_ISGID: int +S_ENFMT = S_ISGID +S_ISVTX: int +S_IREAD: int +S_IWRITE: int +S_IEXEC: int +S_IRWXU: int +S_IRUSR: int +S_IWUSR: int +S_IXUSR: int +S_IRWXG: int +S_IRGRP: int +S_IWGRP: int +S_IXGRP: int +S_IRWXO: int +S_IROTH: int +S_IWOTH: int +S_IXOTH: int +UF_NODUMP: int +UF_IMMUTABLE: int +UF_APPEND: int +UF_OPAQUE: int +UF_NOUNLINK: int +UF_COMPRESSED: int +UF_HIDDEN: int +SF_ARCHIVED: int +SF_IMMUTABLE: int +SF_APPEND: int +SF_NOUNLINK: int +SF_SNAPSHOT: int +_filemode_table: Incomplete + +def filemode(mode): + """Convert a file's mode to a string of the form '-rwxrwxrwx'.""" diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/string.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/string.py new file mode 100644 index 000000000..5937ace51 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/string.py @@ -0,0 +1,27 @@ +# Some strings for ctype-style character classification +whitespace = " \t\n\r\v\f" +ascii_lowercase = "abcdefghijklmnopqrstuvwxyz" +ascii_uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +ascii_letters = ascii_lowercase + ascii_uppercase +digits = "0123456789" +hexdigits = digits + "abcdef" + "ABCDEF" +octdigits = "01234567" +punctuation = """!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~""" +printable = digits + ascii_letters + punctuation + whitespace + + +def translate(s, map): + import io + + sb = io.StringIO() + for c in s: + v = ord(c) + if v in map: + v = map[v] + if isinstance(v, int): + sb.write(chr(v)) + elif v is not None: + sb.write(v) + else: + sb.write(c) + return sb.getvalue() diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/string.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/string.pyi new file mode 100644 index 000000000..86f944bfc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/string.pyi @@ -0,0 +1,13 @@ +from _typeshed import Incomplete + +whitespace: str +ascii_lowercase: str +ascii_uppercase: str +ascii_letters: Incomplete +digits: str +hexdigits: Incomplete +octdigits: str +punctuation: str +printable: Incomplete + +def translate(s, map): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/__init__.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/__init__.py new file mode 100644 index 000000000..9264f6b72 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/__init__.py @@ -0,0 +1,148 @@ +"""Subset of cpython tarfile class methods needed to decode tar files.""" + +import uctypes + +# Minimal set of tar header fields for reading. +# http://www.gnu.org/software/tar/manual/html_node/Standard.html +# The "size" entry is 11 (not 12) to implicitly cut off the null terminator. +_TAR_HEADER = { + "name": (uctypes.ARRAY | 0, uctypes.UINT8 | 100), + "size": (uctypes.ARRAY | 124, uctypes.UINT8 | 11), +} + +DIRTYPE = "dir" +REGTYPE = "file" + +# Constants for TarInfo.isdir, isreg. +_S_IFMT = 0o170000 +_S_IFREG = 0o100000 +_S_IFDIR = 0o040000 + +_BLOCKSIZE = 512 # length of processing blocks + + +def _roundup(val, align): + return (val + align - 1) & ~(align - 1) + + +class FileSection: + def __init__(self, f, content_len, aligned_len): + self.f = f + self.content_len = content_len + self.align = aligned_len - content_len + + def read(self, sz=65536): + if self.content_len == 0: + return b"" + if sz > self.content_len: + sz = self.content_len + data = self.f.read(sz) + sz = len(data) + self.content_len -= sz + return data + + def readinto(self, buf): + if self.content_len == 0: + return 0 + if len(buf) > self.content_len: + buf = memoryview(buf)[: self.content_len] + sz = self.f.readinto(buf) + self.content_len -= sz + return sz + + def skip(self): + sz = self.content_len + self.align + if sz: + buf = bytearray(16) + while sz: + s = min(sz, 16) + self.f.readinto(buf, s) + sz -= s + + +class TarInfo: + def __init__(self, name=""): + self.name = name + self.mode = _S_IFDIR if self.name[-1] == "/" else _S_IFREG + + @property + def type(self): + return DIRTYPE if self.isdir() else REGTYPE + + def __str__(self): + return "TarInfo(%r, %s, %d)" % (self.name, self.type, self.size) + + def isdir(self): + return (self.mode & _S_IFMT) == _S_IFDIR + + def isreg(self): + return (self.mode & _S_IFMT) == _S_IFREG + + +class TarFile: + def __init__(self, name=None, mode="r", fileobj=None): + self.subf = None + self.mode = mode + self.offset = 0 + if mode == "r": + if fileobj: + self.f = fileobj + else: + self.f = open(name, "rb") + else: + try: + self._open_write(name=name, mode=mode, fileobj=fileobj) + except AttributeError: + raise NotImplementedError("Install tarfile-write") + + def __enter__(self): + return self + + def __exit__(self, unused_type, unused_value, unused_traceback): + self.close() + + def next(self): + if self.subf: + self.subf.skip() + buf = self.f.read(_BLOCKSIZE) + if not buf: + return None + + h = uctypes.struct(uctypes.addressof(buf), _TAR_HEADER, uctypes.LITTLE_ENDIAN) + + # Empty block means end of archive + if h.name[0] == 0: + return None + + # Update the offset once we're sure it's not the run-out. + self.offset += len(buf) + d = TarInfo(str(h.name, "utf-8").rstrip("\0")) + d.size = int(bytes(h.size), 8) + self.subf = d.subf = FileSection(self.f, d.size, _roundup(d.size, _BLOCKSIZE)) + self.offset += _roundup(d.size, _BLOCKSIZE) + return d + + def __iter__(self): + return self + + def __next__(self): + v = self.next() + if v is None: + raise StopIteration + return v + + def extractfile(self, tarinfo): + return tarinfo.subf + + def close(self): + try: + self._close_write() + except AttributeError: + pass + self.f.close() + + # Add additional methods to support write/append from the tarfile-write package. + try: + from .write import _open_write, _close_write, addfile, add + except ImportError: + pass diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/__init__.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/__init__.pyi new file mode 100644 index 000000000..29aa98d5e --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/__init__.pyi @@ -0,0 +1,46 @@ +import types +from .write import _close_write as _close_write, _open_write as _open_write, add as add, addfile as addfile +from _typeshed import Incomplete + +_TAR_HEADER: Incomplete +DIRTYPE: str +REGTYPE: str +_S_IFMT: int +_S_IFREG: int +_S_IFDIR: int +_BLOCKSIZE: int + +def _roundup(val, align): ... + +class FileSection: + f: Incomplete + content_len: Incomplete + align: Incomplete + def __init__(self, f, content_len, aligned_len) -> None: ... + def read(self, sz: int = 65536): ... + def readinto(self, buf): ... + def skip(self) -> None: ... + +class TarInfo: + name: Incomplete + mode: Incomplete + def __init__(self, name: str = '') -> None: ... + @property + def type(self): ... + def __str__(self) -> str: ... + def isdir(self): ... + def isreg(self): ... + +class TarFile: + subf: Incomplete + mode: Incomplete + offset: int + f: Incomplete + def __init__(self, name=None, mode: str = 'r', fileobj=None) -> None: ... + def __enter__(self): ... + def __exit__(self, unused_type: type[BaseException] | None, unused_value: BaseException | None, unused_traceback: types.TracebackType | None) -> None: ... + def next(self): ... + def __iter__(self): ... + def __next__(self): ... + def extractfile(self, tarinfo): ... + def close(self) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/write.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/write.py new file mode 100644 index 000000000..b7010d984 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/write.py @@ -0,0 +1,121 @@ +"""Additions to the TarFile class to support creating and appending tar files. + +The methods defined below in are injected into the TarFile class in the +tarfile package. +""" + +import uctypes +import os + +# Extended subset of tar header fields including the ones we'll write. +# http://www.gnu.org/software/tar/manual/html_node/Standard.html +_TAR_HEADER = { + "name": (uctypes.ARRAY | 0, uctypes.UINT8 | 100), + "mode": (uctypes.ARRAY | 100, uctypes.UINT8 | 8), + "uid": (uctypes.ARRAY | 108, uctypes.UINT8 | 8), + "gid": (uctypes.ARRAY | 116, uctypes.UINT8 | 8), + "size": (uctypes.ARRAY | 124, uctypes.UINT8 | 12), + "mtime": (uctypes.ARRAY | 136, uctypes.UINT8 | 12), + "chksum": (uctypes.ARRAY | 148, uctypes.UINT8 | 8), + "typeflag": (uctypes.ARRAY | 156, uctypes.UINT8 | 1), +} + + +_NUL = const(b"\0") # the null character +_BLOCKSIZE = 512 # length of processing blocks +_RECORDSIZE = _BLOCKSIZE * 20 # length of records + + +def _open_write(self, name, mode, fileobj): + if mode == "w": + if not fileobj: + self.f = open(name, "wb") + else: + self.f = fileobj + elif mode == "a": + if not fileobj: + self.f = open(name, "r+b") + else: + self.f = fileobj + # Read through the existing file. + while self.next(): + pass + # Position at start of end block. + self.f.seek(self.offset) + else: + raise ValueError("mode " + mode + " not supported.") + + +def _close_write(self): + # Must be called to complete writing a tar file. + if self.mode == "w": + self.f.write(_NUL * (_BLOCKSIZE * 2)) + self.offset += _BLOCKSIZE * 2 + remainder = self.offset % _RECORDSIZE + if remainder: + self.f.write(_NUL * (_RECORDSIZE - remainder)) + + +def addfile(self, tarinfo, fileobj=None): + # Write the header: 100 bytes of name, 8 bytes of mode in octal... + buf = bytearray(_BLOCKSIZE) + name = tarinfo.name + size = tarinfo.size + if tarinfo.isdir(): + size = 0 + if not name.endswith("/"): + name += "/" + hdr = uctypes.struct(uctypes.addressof(buf), _TAR_HEADER, uctypes.LITTLE_ENDIAN) + hdr.name[:] = name.encode("utf-8")[:100] + hdr.mode[:] = b"%07o\0" % ((0o755 if tarinfo.isdir() else 0o644) & 0o7777) + hdr.uid[:] = b"%07o\0" % tarinfo.uid + hdr.gid[:] = b"%07o\0" % tarinfo.gid + hdr.size[:] = b"%011o\0" % size + hdr.mtime[:] = b"%011o\0" % tarinfo.mtime + hdr.typeflag[:] = b"5" if tarinfo.isdir() else b"0" + # Checksum is calculated with checksum field all blanks. + hdr.chksum[:] = b" " + # Calculate and insert the actual checksum. + chksum = sum(buf) + hdr.chksum[:] = b"%06o\0 " % chksum + # Emit the header. + self.f.write(buf) + self.offset += len(buf) + + # Copy the file contents, if any. + if fileobj: + n_bytes = self.f.write(fileobj.read()) + self.offset += n_bytes + remains = -n_bytes & (_BLOCKSIZE - 1) # == 0b111111111 + if remains: + buf = bytearray(remains) + self.f.write(buf) + self.offset += len(buf) + + +def add(self, name, recursive=True): + from . import TarInfo + + try: + stat = os.stat(name) + res_name = (name + "/") if (stat[0] & 0xF000) == 0x4000 else name + tarinfo = TarInfo(res_name) + tarinfo.mode = stat[0] + tarinfo.uid = stat[4] + tarinfo.gid = stat[5] + tarinfo.size = stat[6] + tarinfo.mtime = stat[8] + except OSError: + print("Cannot stat", name, " - skipping.") + return + if not (tarinfo.isdir() or tarinfo.isreg()): + # We only accept directories or regular files. + print(name, "is not a directory or regular file - skipping.") + return + if tarinfo.isdir(): + self.addfile(tarinfo) + if recursive: + for f in os.ilistdir(name): + self.add(name + "/" + f[0], recursive) + else: # type == REGTYPE + self.addfile(tarinfo, open(name, "rb")) diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/write.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/write.pyi new file mode 100644 index 000000000..7265abdf5 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/tarfile/write.pyi @@ -0,0 +1,11 @@ +from _typeshed import Incomplete + +_TAR_HEADER: Incomplete +_NUL: Incomplete +_BLOCKSIZE: int +_RECORDSIZE: Incomplete + +def _open_write(self, name, mode, fileobj) -> None: ... +def _close_write(self) -> None: ... +def addfile(self, tarinfo, fileobj=None) -> None: ... +def add(self, name, recursive: bool = True) -> None: ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/time.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/time.py new file mode 100644 index 000000000..f79ab8a3b --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/time.py @@ -0,0 +1,79 @@ +from utime import * +from micropython import const + +_TS_YEAR = 0 +_TS_MON = 1 +_TS_MDAY = 2 +_TS_HOUR = 3 +_TS_MIN = 4 +_TS_SEC = 5 +_TS_WDAY = 6 +_TS_YDAY = 7 +_TS_ISDST = 8 + +_WDAY = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") +_MDAY = const( + ( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ) +) + + +def strftime(datefmt, ts): + from io import StringIO + + fmtsp = False + ftime = StringIO() + for k in datefmt: + if fmtsp: + if k == "a": + ftime.write(_WDAY[ts[_TS_WDAY]][0:3]) + elif k == "A": + ftime.write(_WDAY[ts[_TS_WDAY]]) + elif k == "b": + ftime.write(_MDAY[ts[_TS_MON] - 1][0:3]) + elif k == "B": + ftime.write(_MDAY[ts[_TS_MON] - 1]) + elif k == "d": + ftime.write("%02d" % ts[_TS_MDAY]) + elif k == "H": + ftime.write("%02d" % ts[_TS_HOUR]) + elif k == "I": + ftime.write("%02d" % (ts[_TS_HOUR] % 12)) + elif k == "j": + ftime.write("%03d" % ts[_TS_YDAY]) + elif k == "m": + ftime.write("%02d" % ts[_TS_MON]) + elif k == "M": + ftime.write("%02d" % ts[_TS_MIN]) + elif k == "P": + ftime.write("AM" if ts[_TS_HOUR] < 12 else "PM") + elif k == "S": + ftime.write("%02d" % ts[_TS_SEC]) + elif k == "w": + ftime.write(str(ts[_TS_WDAY])) + elif k == "y": + ftime.write("%02d" % (ts[_TS_YEAR] % 100)) + elif k == "Y": + ftime.write(str(ts[_TS_YEAR])) + else: + ftime.write(k) + fmtsp = False + elif k == "%": + fmtsp = True + else: + ftime.write(k) + val = ftime.getvalue() + ftime.close() + return val diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/time.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/time.pyi new file mode 100644 index 000000000..26b0e4b08 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/time.pyi @@ -0,0 +1,59 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. +""" + +from __future__ import annotations +from utime import * +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TS_YEAR: int +_TS_MON: int +_TS_MDAY: int +_TS_HOUR: int +_TS_MIN: int +_TS_SEC: int +_TS_WDAY: int +_TS_YDAY: int +_TS_ISDST: int +_WDAY: Incomplete +_MDAY: Incomplete +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def strftime(datefmt, ts): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/types.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/types.py new file mode 100644 index 000000000..15d983fdc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/types.py @@ -0,0 +1,120 @@ +""" +Define names for built-in types that aren't directly accessible as a builtin. +""" + +import sys + +# Iterators in Python aren't a matter of type but of protocol. A large +# and changing number of builtin types implement *some* flavor of +# iterator. Don't check the type! Use hasattr to check for both +# "__iter__" and "__next__" attributes instead. + + +def _f(): + pass + + +FunctionType = type(_f) +LambdaType = type(lambda: None) # Same as FunctionType +CodeType = None # TODO: Add better sentinel which can't match anything +MappingProxyType = None # TODO: Add better sentinel which can't match anything +SimpleNamespace = None # TODO: Add better sentinel which can't match anything + + +def _g(): + yield 1 + + +GeneratorType = type(_g()) + + +class _C: + def _m(self): + pass + + +MethodType = type(_C()._m) + +BuiltinFunctionType = type(len) +BuiltinMethodType = type([].append) # Same as BuiltinFunctionType + +ModuleType = type(sys) + +try: + raise TypeError +except TypeError: + # tb = sys.exc_info()[2] + TracebackType = None # TODO: Add better sentinel which can't match anything + FrameType = None # TODO: Add better sentinel which can't match anything + tb = None + del tb + +# For Jython, the following two types are identical +GetSetDescriptorType = None # TODO: Add better sentinel which can't match anything +MemberDescriptorType = None # TODO: Add better sentinel which can't match anything + +del ( + sys, + _f, + _g, + _C, +) # Not for export + + +# Provide a PEP 3115 compliant mechanism for class creation +def new_class(name, bases=(), kwds=None, exec_body=None): + """Create a class object dynamically using the appropriate metaclass.""" + meta, ns, kwds = prepare_class(name, bases, kwds) + if exec_body is not None: + exec_body(ns) + return meta(name, bases, ns, **kwds) + + +def prepare_class(name, bases=(), kwds=None): + """Call the __prepare__ method of the appropriate metaclass. + + Returns (metaclass, namespace, kwds) as a 3-tuple + + *metaclass* is the appropriate metaclass + *namespace* is the prepared class namespace + *kwds* is an updated copy of the passed in kwds argument with any + 'metaclass' entry removed. If no kwds argument is passed in, this will + be an empty dict. + """ + if kwds is None: + kwds = {} + else: + kwds = dict(kwds) # Don't alter the provided mapping + if "metaclass" in kwds: + meta = kwds.pop("metaclass") + else: + if bases: + meta = type(bases[0]) + else: + meta = type + if isinstance(meta, type): + # when meta is a type, we first determine the most-derived metaclass + # instead of invoking the initial candidate directly + meta = _calculate_meta(meta, bases) + if hasattr(meta, "__prepare__"): + ns = meta.__prepare__(name, bases, **kwds) + else: + ns = {} + return meta, ns, kwds + + +def _calculate_meta(meta, bases): + """Calculate the most derived metaclass.""" + winner = meta + for base in bases: + base_meta = type(base) + if issubclass(winner, base_meta): + continue + if issubclass(base_meta, winner): + winner = base_meta + continue + # else: + raise TypeError( + "metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases" + ) + return winner diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/types.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/types.pyi new file mode 100644 index 000000000..4200650c3 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/types.pyi @@ -0,0 +1,45 @@ +from _typeshed import Incomplete +from collections.abc import Generator + +def _f() -> None: ... + +FunctionType: Incomplete +LambdaType: Incomplete +CodeType: Incomplete +MappingProxyType: Incomplete +SimpleNamespace: Incomplete + +def _g() -> Generator[Incomplete]: ... + +GeneratorType: Incomplete + +class _C: + def _m(self) -> None: ... + +MethodType: Incomplete +BuiltinFunctionType: Incomplete +BuiltinMethodType: Incomplete +ModuleType: Incomplete +TracebackType: Incomplete +FrameType: Incomplete +tb: Incomplete +GetSetDescriptorType: Incomplete +MemberDescriptorType: Incomplete + +def new_class(name, bases=(), kwds=None, exec_body=None): + """Create a class object dynamically using the appropriate metaclass.""" + +def prepare_class(name, bases=(), kwds=None): + """Call the __prepare__ method of the appropriate metaclass. + + Returns (metaclass, namespace, kwds) as a 3-tuple + + *metaclass* is the appropriate metaclass + *namespace* is the prepared class namespace + *kwds* is an updated copy of the passed in kwds argument with any + 'metaclass' entry removed. If no kwds argument is passed in, this will + be an empty dict. + """ + +def _calculate_meta(meta, bases): + """Calculate the most derived metaclass.""" diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/unittest/__init__.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/unittest/__init__.py new file mode 100644 index 000000000..4f4ca2849 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/unittest/__init__.py @@ -0,0 +1,463 @@ +import io +import sys + +try: + import traceback +except ImportError: + traceback = None + + +class SkipTest(Exception): + pass + + +class AssertRaisesContext: + def __init__(self, exc): + self.expected = exc + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + self.exception = exc_value + if exc_type is None: + assert False, "%r not raised" % self.expected + if issubclass(exc_type, self.expected): + # store exception for later retrieval + self.exception = exc_value + return True + return False + + +# These are used to provide required context to things like subTest +__current_test__ = None +__test_result__ = None + + +class SubtestContext: + def __init__(self, msg=None, params=None): + self.msg = msg + self.params = params + + def __enter__(self): + pass + + def __exit__(self, *exc_info): + if exc_info[0] is not None: + # Exception raised + global __test_result__, __current_test__ + test_details = __current_test__ + if self.msg: + test_details += (f" [{self.msg}]",) + if self.params: + detail = ", ".join(f"{k}={v}" for k, v in self.params.items()) + test_details += (f" ({detail})",) + + _handle_test_exception(test_details, __test_result__, exc_info, False) + # Suppress the exception as we've captured it above + return True + + +class NullContext: + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + pass + + +class TestCase: + def __init__(self): + pass + + def addCleanup(self, func, *args, **kwargs): + if not hasattr(self, "_cleanups"): + self._cleanups = [] + self._cleanups.append((func, args, kwargs)) + + def doCleanups(self): + if hasattr(self, "_cleanups"): + while self._cleanups: + func, args, kwargs = self._cleanups.pop() + func(*args, **kwargs) + + def subTest(self, msg=None, **params): + return SubtestContext(msg=msg, params=params) + + def skipTest(self, reason): + raise SkipTest(reason) + + def fail(self, msg=""): + assert False, msg + + def assertEqual(self, x, y, msg=""): + if not msg: + msg = "%r vs (expected) %r" % (x, y) + assert x == y, msg + + def assertNotEqual(self, x, y, msg=""): + if not msg: + msg = "%r not expected to be equal %r" % (x, y) + assert x != y, msg + + def assertLessEqual(self, x, y, msg=None): + if msg is None: + msg = "%r is expected to be <= %r" % (x, y) + assert x <= y, msg + + def assertGreaterEqual(self, x, y, msg=None): + if msg is None: + msg = "%r is expected to be >= %r" % (x, y) + assert x >= y, msg + + def assertAlmostEqual(self, x, y, places=None, msg="", delta=None): + if x == y: + return + if delta is not None and places is not None: + raise TypeError("specify delta or places not both") + + if delta is not None: + if abs(x - y) <= delta: + return + if not msg: + msg = "%r != %r within %r delta" % (x, y, delta) + else: + if places is None: + places = 7 + if round(abs(y - x), places) == 0: + return + if not msg: + msg = "%r != %r within %r places" % (x, y, places) + + assert False, msg + + def assertNotAlmostEqual(self, x, y, places=None, msg="", delta=None): + if delta is not None and places is not None: + raise TypeError("specify delta or places not both") + + if delta is not None: + if not (x == y) and abs(x - y) > delta: + return + if not msg: + msg = "%r == %r within %r delta" % (x, y, delta) + else: + if places is None: + places = 7 + if not (x == y) and round(abs(y - x), places) != 0: + return + if not msg: + msg = "%r == %r within %r places" % (x, y, places) + + assert False, msg + + def assertIs(self, x, y, msg=""): + if not msg: + msg = "%r is not %r" % (x, y) + assert x is y, msg + + def assertIsNot(self, x, y, msg=""): + if not msg: + msg = "%r is %r" % (x, y) + assert x is not y, msg + + def assertIsNone(self, x, msg=""): + if not msg: + msg = "%r is not None" % x + assert x is None, msg + + def assertIsNotNone(self, x, msg=""): + if not msg: + msg = "%r is None" % x + assert x is not None, msg + + def assertTrue(self, x, msg=""): + if not msg: + msg = "Expected %r to be True" % x + assert x, msg + + def assertFalse(self, x, msg=""): + if not msg: + msg = "Expected %r to be False" % x + assert not x, msg + + def assertIn(self, x, y, msg=""): + if not msg: + msg = "Expected %r to be in %r" % (x, y) + assert x in y, msg + + def assertIsInstance(self, x, y, msg=""): + assert isinstance(x, y), msg + + def assertRaises(self, exc, func=None, *args, **kwargs): + if func is None: + return AssertRaisesContext(exc) + + try: + func(*args, **kwargs) + except Exception as e: + if isinstance(e, exc): + return + raise e + + assert False, "%r not raised" % exc + + def assertWarns(self, warn): + return NullContext() + + +def skip(msg): + def _decor(fun): + # We just replace original fun with _inner + def _inner(self): + raise SkipTest(msg) + + return _inner + + return _decor + + +def skipIf(cond, msg): + if not cond: + return lambda x: x + return skip(msg) + + +def skipUnless(cond, msg): + if cond: + return lambda x: x + return skip(msg) + + +def expectedFailure(test): + def test_exp_fail(*args, **kwargs): + try: + test(*args, **kwargs) + except: + pass + else: + assert False, "unexpected success" + + return test_exp_fail + + +class TestSuite: + def __init__(self, name=""): + self._tests = [] + self.name = name + + def addTest(self, cls): + self._tests.append(cls) + + def run(self, result): + for c in self._tests: + _run_suite(c, result, self.name) + return result + + def _load_module(self, mod): + for tn in dir(mod): + c = getattr(mod, tn) + if isinstance(c, object) and isinstance(c, type) and issubclass(c, TestCase): + self.addTest(c) + elif tn.startswith("test") and callable(c): + self.addTest(c) + + +class TestRunner: + def run(self, suite: TestSuite): + res = TestResult() + suite.run(res) + + res.printErrors() + print("----------------------------------------------------------------------") + print("Ran %d tests\n" % res.testsRun) + if res.failuresNum > 0 or res.errorsNum > 0: + print("FAILED (failures=%d, errors=%d)" % (res.failuresNum, res.errorsNum)) + else: + msg = "OK" + if res.skippedNum > 0: + msg += " (skipped=%d)" % res.skippedNum + print(msg) + + return res + + +TextTestRunner = TestRunner + + +class TestResult: + def __init__(self): + self.errorsNum = 0 + self.failuresNum = 0 + self.skippedNum = 0 + self.testsRun = 0 + self.errors = [] + self.failures = [] + self.skipped = [] + self._newFailures = 0 + + def wasSuccessful(self): + return self.errorsNum == 0 and self.failuresNum == 0 + + def printErrors(self): + if self.errors or self.failures: + print() + self.printErrorList(self.errors) + self.printErrorList(self.failures) + + def printErrorList(self, lst): + sep = "----------------------------------------------------------------------" + for c, e in lst: + detail = " ".join((str(i) for i in c)) + print("======================================================================") + print(f"FAIL: {detail}") + print(sep) + print(e) + + def __repr__(self): + # Format is compatible with CPython. + return "" % ( + self.testsRun, + self.errorsNum, + self.failuresNum, + ) + + def __add__(self, other): + self.errorsNum += other.errorsNum + self.failuresNum += other.failuresNum + self.skippedNum += other.skippedNum + self.testsRun += other.testsRun + self.errors.extend(other.errors) + self.failures.extend(other.failures) + self.skipped.extend(other.skipped) + return self + + +def _capture_exc(exc, exc_traceback): + buf = io.StringIO() + if hasattr(sys, "print_exception"): + sys.print_exception(exc, buf) + elif traceback is not None: + traceback.print_exception(None, exc, exc_traceback, file=buf) + return buf.getvalue() + + +def _handle_test_exception( + current_test: tuple, test_result: TestResult, exc_info: tuple, verbose=True +): + exc = exc_info[1] + traceback = exc_info[2] + ex_str = _capture_exc(exc, traceback) + if isinstance(exc, SkipTest): + reason = exc.args[0] + test_result.skippedNum += 1 + test_result.skipped.append((current_test, reason)) + print(" skipped:", reason) + return + elif isinstance(exc, AssertionError): + test_result.failuresNum += 1 + test_result.failures.append((current_test, ex_str)) + if verbose: + print(" FAIL") + else: + test_result.errorsNum += 1 + test_result.errors.append((current_test, ex_str)) + if verbose: + print(" ERROR") + test_result._newFailures += 1 + + +def _run_suite(c, test_result: TestResult, suite_name=""): + if isinstance(c, TestSuite): + c.run(test_result) + return + + if isinstance(c, type): + o = c() + else: + o = c + set_up_class = getattr(o, "setUpClass", lambda: None) + tear_down_class = getattr(o, "tearDownClass", lambda: None) + set_up = getattr(o, "setUp", lambda: None) + tear_down = getattr(o, "tearDown", lambda: None) + exceptions = [] + try: + suite_name += "." + c.__qualname__ + except AttributeError: + pass + + def run_one(test_function): + global __test_result__, __current_test__ + print("%s (%s) ..." % (name, suite_name), end="") + set_up() + __test_result__ = test_result + test_container = f"({suite_name})" + __current_test__ = (name, test_container) + try: + test_result._newFailures = 0 + test_result.testsRun += 1 + test_function() + # No exception occurred, test passed + if test_result._newFailures: + print(" FAIL") + else: + print(" ok") + except Exception as ex: + _handle_test_exception( + current_test=(name, c), test_result=test_result, exc_info=(type(ex), ex, None) + ) + # Uncomment to investigate failure in detail + # raise ex + finally: + __test_result__ = None + __current_test__ = None + tear_down() + try: + o.doCleanups() + except AttributeError: + pass + + set_up_class() + try: + if hasattr(o, "runTest"): + name = str(o) + run_one(o.runTest) + return + + for name in dir(o): + if name.startswith("test"): + m = getattr(o, name) + if not callable(m): + continue + run_one(m) + + if callable(o): + name = o.__name__ + run_one(o) + finally: + tear_down_class() + + return exceptions + + +# This supports either: +# +# >>> import mytest +# >>> unitttest.main(mytest) +# +# >>> unittest.main("mytest") +# +# Or, a script that ends with: +# if __name__ == "__main__": +# unittest.main() +# e.g. run via `mpremote run mytest.py` +def main(module="__main__", testRunner=None): + if testRunner is None: + testRunner = TestRunner() + elif isinstance(testRunner, type): + testRunner = testRunner() + + if isinstance(module, str): + module = __import__(module) + suite = TestSuite(module.__name__) + suite._load_module(module) + return testRunner.run(suite) diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/unittest/__init__.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/unittest/__init__.pyi new file mode 100644 index 000000000..071a75777 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/unittest/__init__.pyi @@ -0,0 +1,88 @@ +import types +from _typeshed import Incomplete + +class SkipTest(Exception): ... + +class AssertRaisesContext: + expected: Incomplete + def __init__(self, exc) -> None: ... + def __enter__(self): ... + exception: Incomplete + def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, tb: types.TracebackType | None): ... + +__current_test__: Incomplete +__test_result__: Incomplete + +class SubtestContext: + msg: Incomplete + params: Incomplete + def __init__(self, msg=None, params=None) -> None: ... + def __enter__(self) -> None: ... + def __exit__(self, *exc_info): ... + +class NullContext: + def __enter__(self) -> None: ... + def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: types.TracebackType | None) -> None: ... + +class TestCase: + def __init__(self) -> None: ... + _cleanups: Incomplete + def addCleanup(self, func, *args, **kwargs) -> None: ... + def doCleanups(self) -> None: ... + def subTest(self, msg=None, **params): ... + def skipTest(self, reason) -> None: ... + def fail(self, msg: str = '') -> None: ... + def assertEqual(self, x, y, msg: str = '') -> None: ... + def assertNotEqual(self, x, y, msg: str = '') -> None: ... + def assertLessEqual(self, x, y, msg=None) -> None: ... + def assertGreaterEqual(self, x, y, msg=None) -> None: ... + def assertAlmostEqual(self, x, y, places=None, msg: str = '', delta=None) -> None: ... + def assertNotAlmostEqual(self, x, y, places=None, msg: str = '', delta=None) -> None: ... + def assertIs(self, x, y, msg: str = '') -> None: ... + def assertIsNot(self, x, y, msg: str = '') -> None: ... + def assertIsNone(self, x, msg: str = '') -> None: ... + def assertIsNotNone(self, x, msg: str = '') -> None: ... + def assertTrue(self, x, msg: str = '') -> None: ... + def assertFalse(self, x, msg: str = '') -> None: ... + def assertIn(self, x, y, msg: str = '') -> None: ... + def assertIsInstance(self, x, y, msg: str = '') -> None: ... + def assertRaises(self, exc, func=None, *args, **kwargs): ... + def assertWarns(self, warn): ... + +def skip(msg): ... +def skipIf(cond, msg): ... +def skipUnless(cond, msg): ... +def expectedFailure(test): ... + +class TestSuite: + _tests: Incomplete + name: Incomplete + def __init__(self, name: str = '') -> None: ... + def addTest(self, cls) -> None: ... + def run(self, result): ... + def _load_module(self, mod) -> None: ... + +class TestRunner: + def run(self, suite: TestSuite): ... +TextTestRunner = TestRunner + +class TestResult: + errorsNum: int + failuresNum: int + skippedNum: int + testsRun: int + errors: Incomplete + failures: Incomplete + skipped: Incomplete + _newFailures: int + def __init__(self) -> None: ... + def wasSuccessful(self): ... + def printErrors(self) -> None: ... + def printErrorList(self, lst) -> None: ... + def __repr__(self) -> str: ... + def __add__(self, other): ... + +def _capture_exc(exc, exc_traceback): ... +def _handle_test_exception(current_test: tuple, test_result: TestResult, exc_info: tuple, verbose: bool = True): ... +def _run_suite(c, test_result: TestResult, suite_name: str = ''): ... +def main(module: str = '__main__', testRunner=None): ... diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/uu.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/uu.py new file mode 100644 index 000000000..03f8b2df1 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/uu.py @@ -0,0 +1,218 @@ +#! /usr/bin/env python3 + +# Copyright 1994 by Lance Ellinghouse +# Cathedral City, California Republic, United States of America. +# All Rights Reserved +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose and without fee is hereby granted, +# provided that the above copyright notice appear in all copies and that +# both that copyright notice and this permission notice appear in +# supporting documentation, and that the name of Lance Ellinghouse +# not be used in advertising or publicity pertaining to distribution +# of the software without specific, written prior permission. +# LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO +# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE CENTRUM BE LIABLE +# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# Modified by Jack Jansen, CWI, July 1995: +# - Use binascii module to do the actual line-by-line conversion +# between ascii and binary. This results in a 1000-fold speedup. The C +# version is still 5 times faster, though. +# - Arguments more compliant with python standard + +"""Implementation of the UUencode and UUdecode functions. + +encode(in_file, out_file [,name, mode]) +decode(in_file [, out_file, mode]) +""" + +import binascii +import os +import sys + +__all__ = ["Error", "encode", "decode"] + + +class Error(Exception): + pass + + +def encode(in_file, out_file, name=None, mode=None): + """Uuencode file""" + # + # If in_file is a pathname open it and change defaults + # + opened_files = [] + try: + if in_file == "-": + in_file = sys.stdin.buffer + elif isinstance(in_file, str): + if name is None: + name = os.path.basename(in_file) + if mode is None: + try: + mode = os.stat(in_file).st_mode + except AttributeError: + pass + in_file = open(in_file, "rb") + opened_files.append(in_file) + # + # Open out_file if it is a pathname + # + if out_file == "-": + out_file = sys.stdout.buffer + elif isinstance(out_file, str): + out_file = open(out_file, "wb") + opened_files.append(out_file) + # + # Set defaults for name and mode + # + if name is None: + name = "-" + if mode is None: + mode = 0o666 + # + # Write the data + # + out_file.write(("begin %o %s\n" % ((mode & 0o777), name)).encode("ascii")) + data = in_file.read(45) + while len(data) > 0: + out_file.write(binascii.b2a_uu(data)) + data = in_file.read(45) + out_file.write(b" \nend\n") + finally: + for f in opened_files: + f.close() + + +def decode(in_file, out_file=None, mode=None, quiet=False): + """Decode uuencoded file""" + # + # Open the input file, if needed. + # + opened_files = [] + if in_file == "-": + in_file = sys.stdin.buffer + elif isinstance(in_file, str): + in_file = open(in_file, "rb") + opened_files.append(in_file) + + try: + # + # Read until a begin is encountered or we've exhausted the file + # + while True: + hdr = in_file.readline() + if not hdr: + raise Error("No valid begin line found in input file") + if not hdr.startswith(b"begin"): + continue + hdrfields = hdr.split(b" ", 2) + if len(hdrfields) == 3 and hdrfields[0] == b"begin": + try: + int(hdrfields[1], 8) + break + except ValueError: + pass + if out_file is None: + # If the filename isn't ASCII, what's up with that?!? + out_file = hdrfields[2].rstrip(b" \t\r\n\f").decode("ascii") + if os.path.exists(out_file): + raise Error("Cannot overwrite existing file: %s" % out_file) + if mode is None: + mode = int(hdrfields[1], 8) + # + # Open the output file + # + if out_file == "-": + out_file = sys.stdout.buffer + elif isinstance(out_file, str): + fp = open(out_file, "wb") + try: + os.path.chmod(out_file, mode) + except AttributeError: + pass + out_file = fp + opened_files.append(out_file) + # + # Main decoding loop + # + s = in_file.readline() + while s and s.strip(b" \t\r\n\f") != b"end": + try: + data = binascii.a2b_uu(s) + except binascii.Error as v: + # Workaround for broken uuencoders by /Fredrik Lundh + nbytes = (((s[0] - 32) & 63) * 4 + 5) // 3 + data = binascii.a2b_uu(s[:nbytes]) + if not quiet: + sys.stderr.write("Warning: %s\n" % v) + out_file.write(data) + s = in_file.readline() + if not s: + raise Error("Truncated input file") + finally: + for f in opened_files: + f.close() + + +def test(): + """uuencode/uudecode main program""" + + import optparse + + parser = optparse.OptionParser(usage="usage: %prog [-d] [-t] [input [output]]") + parser.add_option( + "-d", + "--decode", + dest="decode", + help="Decode (instead of encode)?", + default=False, + action="store_true", + ) + parser.add_option( + "-t", + "--text", + dest="text", + help="data is text, encoded format unix-compatible text?", + default=False, + action="store_true", + ) + + (options, args) = parser.parse_args() + if len(args) > 2: + parser.error("incorrect number of arguments") + sys.exit(1) + + # Use the binary streams underlying stdin/stdout + input = sys.stdin.buffer + output = sys.stdout.buffer + if len(args) > 0: + input = args[0] + if len(args) > 1: + output = args[1] + + if options.decode: + if options.text: + if isinstance(output, str): + output = open(output, "wb") + else: + print(sys.argv[0], ": cannot do -t to stdout") + sys.exit(1) + decode(input, output) + else: + if options.text: + if isinstance(input, str): + input = open(input, "rb") + else: + print(sys.argv[0], ": cannot do -t from stdin") + sys.exit(1) + encode(input, output) + + +if __name__ == "__main__": + test() diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/uu.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/uu.pyi new file mode 100644 index 000000000..b095f7422 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/uu.pyi @@ -0,0 +1,9 @@ +__all__ = ["Error", "encode", "decode"] + +class Error(Exception): ... + +def encode(in_file, out_file, name=None, mode=None) -> None: + """Uuencode file""" + +def decode(in_file, out_file=None, mode=None, quiet: bool = False) -> None: + """Decode uuencoded file""" diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/zlib.py b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/zlib.py new file mode 100644 index 000000000..c8cadf092 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/zlib.py @@ -0,0 +1,39 @@ +# MicroPython zlib module +# MIT license; Copyright (c) 2023 Jim Mussared + +import io, deflate + +_MAX_WBITS = 15 + + +def _decode_wbits(wbits, decompress): + if -15 <= wbits <= -5: + return ( + deflate.RAW, + -wbits, + ) + elif 5 <= wbits <= 15: + return (deflate.ZLIB, wbits) + elif decompress and wbits == 0: + return (deflate.ZLIB,) + elif 21 <= wbits <= 31: + return (deflate.GZIP, wbits - 16) + elif decompress and 35 <= wbits <= 47: + return (deflate.AUTO, wbits - 32) + else: + raise ValueError("wbits") + + +if hasattr(deflate.DeflateIO, "write"): + + def compress(data, wbits=_MAX_WBITS): + f = io.BytesIO() + with deflate.DeflateIO(f, *_decode_wbits(wbits, False)) as g: + g.write(data) + return f.getvalue() + + +def decompress(data, wbits=_MAX_WBITS): + f = io.BytesIO(data) + with deflate.DeflateIO(f, *_decode_wbits(wbits, True)) as g: + return g.read() diff --git a/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/zlib.pyi b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/zlib.pyi new file mode 100644 index 000000000..a1a42a8bd --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/webassembly/GENERIC/zlib.pyi @@ -0,0 +1,90 @@ +""" +Zlib compression & decompression. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/zlib.html + +CPython module: :mod:`python:zlib` https://docs.python.org/3/library/zlib.html . + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ +(commonly used in the zlib library and gzip archiver). + +``Note:`` Prefer to use :class:`deflate.DeflateIO` instead of the functions in this + module as it provides a streaming interface to compression and decompression + which is convenient and more memory efficient when working with reading or + writing compressed data to a file, socket, or stream. + +**Availability:** + +* From MicroPython v1.21 onwards, this module may not be present by default on + all MicroPython firmware as it duplicates functionality available in + the :mod:`deflate ` module. + +* A copy of this module can be installed (or frozen) + from :term:`micropython-lib` (`source `_). + See :ref:`packages` for more information. This documentation describes that module. + +* Requires the built-in :mod:`deflate ` module (available since MicroPython v1.21) + +* Compression support will only be available if compression support is enabled + in the built-in :mod:`deflate ` module. +""" + +from __future__ import annotations +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_MAX_WBITS: int + +def _decode_wbits(wbits, decompress): ... +def compress(data, wbits=...) -> Incomplete: + """ + Compresses *data* into a bytes object. + + *wbits* allows you to configure the DEFLATE dictionary window size and the + output format. The window size allows you to trade-off memory usage for + compression level. A larger window size will allow the compressor to + reference fragments further back in the input. The output formats are "raw" + DEFLATE (no header/footer), zlib, and gzip, where the latter two + include a header and checksum. + + The low four bits of the absolute value of *wbits* set the base-2 logarithm of + the DEFLATE dictionary window size. So for example, ``wbits=10``, + ``wbits=-10``, and ``wbits=26`` all set the window size to 1024 bytes. Valid + window sizes are ``5`` to ``15`` inclusive (corresponding to 32 to 32k bytes). + + Negative values of *wbits* between ``-5`` and ``-15`` correspond to "raw" + output mode, positive values between ``5`` and ``15`` correspond to zlib + output mode, and positive values between ``21`` and ``31`` correspond to + gzip output mode. + + See the :mod:`CPython documentation for zlib ` for more + information about the *wbits* parameter. Note that MicroPython allows + for smaller window sizes, which is useful when memory is constrained while + still achieving a reasonable level of compression. It also speeds up + the compressor. See more :ref:`MicroPython-specific details ` + in the :mod:`deflate ` module documentation. + """ + ... + +def decompress(data, wbits=...) -> bytes: + """ + Decompresses *data* into a bytes object. + + The *wbits* parameter works the same way as for :meth:`zlib.compress` + with the following additional valid values: + + * ``0``: Automatically determine the window size from the zlib header + (*data* must be in zlib format). + * ``35`` to ``47``: Auto-detect either the zlib or gzip format. + + As for :meth:`zlib.compress`, see the :mod:`CPython documentation for zlib ` + for more information about the *wbits* parameter. As for :meth:`zlib.compress`, + MicroPython also supports smaller window sizes than CPython. See more + :ref:`MicroPython-specific details ` in the + :mod:`deflate ` module documentation. + + If the data to be decompressed requires a larger window size, it will + fail during decompression. + """ + ... diff --git a/stubs/micropython-v1_26_1-frozen/windows/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/windows/GENERIC/modules.json new file mode 100644 index 000000000..6c221398c --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/windows/GENERIC/modules.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "windows", + "platform": "windows", + "machine": "GENERIC", + "firmware": "micropython-windows-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "ssl.py", + "module": "ssl" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/windows/GENERIC/removed.txt b/stubs/micropython-v1_26_1-frozen/windows/GENERIC/removed.txt new file mode 100644 index 000000000..e1bf350aa --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/windows/GENERIC/removed.txt @@ -0,0 +1,2 @@ +modules removed to avoid incorrect merge effects: +asyncio \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/windows/GENERIC/ssl.py b/stubs/micropython-v1_26_1-frozen/windows/GENERIC/ssl.py new file mode 100644 index 000000000..590c94ac4 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/windows/GENERIC/ssl.py @@ -0,0 +1,63 @@ +import tls +from tls import * + + +class SSLContext: + def __init__(self, *args): + self._context = tls.SSLContext(*args) + self._context.verify_mode = CERT_NONE + + @property + def verify_mode(self): + return self._context.verify_mode + + @verify_mode.setter + def verify_mode(self, val): + self._context.verify_mode = val + + def load_cert_chain(self, certfile, keyfile): + if isinstance(certfile, str): + with open(certfile, "rb") as f: + certfile = f.read() + if isinstance(keyfile, str): + with open(keyfile, "rb") as f: + keyfile = f.read() + self._context.load_cert_chain(certfile, keyfile) + + def load_verify_locations(self, cafile=None, cadata=None): + if cafile: + with open(cafile, "rb") as f: + cadata = f.read() + self._context.load_verify_locations(cadata) + + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None): + return self._context.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake_on_connect, + server_hostname=server_hostname, + ) + + +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + con = SSLContext(PROTOCOL_TLS_SERVER if server_side else PROTOCOL_TLS_CLIENT) + if cert or key: + con.load_cert_chain(cert, key) + if cadata: + con.load_verify_locations(cadata=cadata) + con.verify_mode = cert_reqs + return con.wrap_socket( + sock, + server_side=server_side, + do_handshake_on_connect=do_handshake, + server_hostname=server_hostname, + ) diff --git a/stubs/micropython-v1_26_1-frozen/windows/GENERIC/ssl.pyi b/stubs/micropython-v1_26_1-frozen/windows/GENERIC/ssl.pyi new file mode 100644 index 000000000..5e33aa7dc --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/windows/GENERIC/ssl.pyi @@ -0,0 +1,180 @@ +""" +TLS/SSL wrapper for socket objects. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/ssl.html + +CPython module: :mod:`python:ssl` https://docs.python.org/3/library/ssl.html . + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layer”) encryption and peer authentication +facilities for network sockets, both client-side and server-side. +""" + +from __future__ import annotations +from tls import * +from _typeshed import Incomplete +import socket +from _mpy_shed import StrOrBytesPath, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +PROTOCOL_TLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_TLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_CLIENT: Incomplete +"""Supported values for the *protocol* parameter.""" +PROTOCOL_DTLS_SERVER: Incomplete +"""Supported values for the *protocol* parameter.""" +CERT_NONE: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_OPTIONAL: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +CERT_REQUIRED: Incomplete +"""\ +Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` +attribute. +""" +MBEDTLS_VERSION: str = "Mbed TLS 3.6.0" + +class SSLContext: + """ + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + """ + + _context: Incomplete + def __init__(self, *args) -> None: ... + @property + def verify_mode(self): ... + @verify_mode.setter + def verify_mode(self, val) -> None: ... + @mp_available() # force merge + def load_cert_chain(self, certfile, keyfile) -> None: + """ + Load a private key and the corresponding certificate. The *certfile* is a string + with the file path of the certificate. The *keyfile* is a string with the file path + of the private key. + + Admonition:Difference to CPython + :class: attention + + MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of + strings, in which case they are interpreted as the actual certificate/key data. + """ + ... + def load_verify_locations(self, cafile=None, cadata=None) -> None: + """ + Load the CA certificate chain that will validate the peer's certificate. + *cafile* is the file path of the CA certificates. *cadata* is a bytes object + containing the CA certificates. Only one of these arguments should be provided. + """ + ... + def wrap_socket(self, sock, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname=None) -> SSLSocket: + """ + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. + + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` + or whether it is deferred to be done as part of the initial reads or writes + For blocking sockets doing the handshake immediately is standard. For non-blocking + sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) + the handshake should generally be deferred because otherwise ``wrap_socket`` blocks + until it completes. Note that in AXTLS the handshake can be deferred until the first + read or write but it then blocks until completion. + + - *server_hostname* is for use as a client, and sets the hostname to check against the received + server certificate. It also sets the name for Server Name Indication (SNI), allowing the server + to present the proper certificate. + + - *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS + Server. See :ref:`dtls` for details. + """ + ... + +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +# End duplicated section +# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +@mp_available() # force merge +def wrap_socket( + sock: socket.socket, + *, + server_side: bool = False, + key: Incomplete = None, + cert: Incomplete = None, + cert_reqs: int = 0, + cadata: bytes | None = None, + server_hostname: str | None = None, + do_handshake: bool = True, +) -> SSLSocket: + """ + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + """ + ... + +class SSLSocket: + # TODO : SSLSocket is undocumented + # ref: micropython\extmod\modtls_axtls.c ( read ... close) + + # repos\micropython\extmod\modtls_mbedtls.c + @mp_available() # force merge + def read(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readinto(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def readline(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def write(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def setblocking(self, *argv, **kwargs) -> Incomplete: ... + @mp_available() # force merge + def close(self, *argv, **kwargs) -> Incomplete: ... + # if MICROPY_PY_SSL_FINALISER + @mp_available(macro="MICROPY_PY_SSL_FINALISER") # force merge + def __del__(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef MICROPY_UNIX_COVERAGE + @mp_available(macro="MICROPY_UNIX_COVERAGE") # force merge + def ioctl(self, *argv, **kwargs) -> Incomplete: ... + # endif + # ifdef (MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + @mp_available(macro="MBEDTLS_SSL_KEEP_PEER_CERTIFICATE") # force merge + def getpeercert(self, *argv, **kwargs) -> Incomplete: ... + # endif + @mp_available() # force merge + def cipher(self, *argv, **kwargs) -> Incomplete: ... + # ifdef MBEDTLS_SSL_PROTO_DTLS + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def recv_into(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def send(self, *argv, **kwargs) -> Incomplete: ... + @mp_available(macro="MBEDTLS_SSL_PROTO_DTLS") # force merge + def sendall(self, *argv, **kwargs) -> Incomplete: ... diff --git a/stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/modules.json b/stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/modules.json new file mode 100644 index 000000000..7fe079697 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/modules.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/Josverl/micropython-stubber/main/data/schema/stubber-v1_4_0.json", + "firmware": { + "family": "micropython", + "port": "zephyr", + "platform": "zephyr", + "machine": "GENERIC", + "firmware": "micropython-zephyr-v1_26_1", + "nodename": "micropython", + "version": "v1.26.1", + "release": "v1.26.1", + "sysname": "micropython" + }, + "stubber": { + "version": "1.26.3", + "stubtype": "frozen" + }, + "modules": [ + { + "file": "upysh.py", + "module": "upysh" + } + ] +} \ No newline at end of file diff --git a/stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/upysh.py b/stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/upysh.py new file mode 100644 index 000000000..0f0ad65ba --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/upysh.py @@ -0,0 +1,124 @@ +import sys +import os + + +class LS: + def __repr__(self): + self.__call__() + return "" + + def __call__(self, path="."): + l = list(os.ilistdir(path)) + l.sort() + for f in l: + if f[1] == 0x4000: # stat.S_IFDIR + print(" %s" % f[0]) + for f in l: + if f[1] != 0x4000: + if len(f) > 3: + print("% 9d %s" % (f[3], f[0])) + else: + print(" %s" % f[0]) + try: + st = os.statvfs(path) + print("\n{:,d}k free".format(st[1] * st[3] // 1024)) + except: + pass + + +class PWD: + def __repr__(self): + return os.getcwd() + + def __call__(self): + return self.__repr__() + + +class CLEAR: + def __repr__(self): + return "\x1b[2J\x1b[H" + + def __call__(self): + return self.__repr__() + + +def head(f, n=10): + with open(f) as f: + for i in range(n): + l = f.readline() + if not l: + break + sys.stdout.write(l) + + +def cat(f): + head(f, 1 << 30) + + +def cp(s, t): + try: + if os.stat(t)[0] & 0x4000: # is directory + t = t.rstrip("/") + "/" + s + except OSError: + pass + buf = bytearray(512) + buf_mv = memoryview(buf) + with open(s, "rb") as s, open(t, "wb") as t: + while True: + n = s.readinto(buf) + if n <= 0: + break + t.write(buf_mv[:n]) + + +def newfile(path): + print("Type file contents line by line, finish with EOF (Ctrl+D).") + with open(path, "w") as f: + while 1: + try: + l = input() + except EOFError: + break + f.write(l) + f.write("\n") + + +def rm(d, recursive=False): # Remove file or tree + try: + if (os.stat(d)[0] & 0x4000) and recursive: # Dir + for f in os.ilistdir(d): + if f[0] != "." and f[0] != "..": + rm("/".join((d, f[0]))) # File or Dir + os.rmdir(d) + else: # File + os.remove(d) + except: + print("rm of '%s' failed" % d) + + +class Man: + def __repr__(self): + return """ +upysh is intended to be imported using: +from upysh import * + +To see this help text again, type "man". + +upysh commands: +clear, ls, ls(...), head(...), cat(...), newfile(...) +cp('src', 'dest'), mv('old', 'new'), rm(...) +pwd, cd(...), mkdir(...), rmdir(...) +""" + + +man = Man() +pwd = PWD() +ls = LS() +clear = CLEAR() + +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir + +print(man) diff --git a/stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/upysh.pyi b/stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/upysh.pyi new file mode 100644 index 000000000..393c0abf0 --- /dev/null +++ b/stubs/micropython-v1_26_1-frozen/zephyr/GENERIC/upysh.pyi @@ -0,0 +1,32 @@ +import os +from _typeshed import Incomplete + +class LS: + def __repr__(self) -> str: ... + def __call__(self, path: str = ".") -> None: ... + +class PWD: + def __repr__(self) -> str: ... + def __call__(self): ... + +class CLEAR: + def __repr__(self) -> str: ... + def __call__(self): ... + +def head(f, n: int = 10) -> None: ... +def cat(f) -> None: ... +def cp(s, t) -> None: ... +def newfile(path) -> None: ... +def rm(d, recursive: bool = False) -> None: ... + +class Man: + def __repr__(self) -> str: ... + +man: Incomplete +pwd: Incomplete +ls: Incomplete +clear: Incomplete +cd = os.chdir +mkdir = os.mkdir +mv = os.rename +rmdir = os.rmdir From 2a1dde4893e6af8f83479f27eab5f41e65e4977c Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Wed, 26 Nov 2025 11:33:11 +0100 Subject: [PATCH 4/5] Add MicroPython v1.26.1 mimxrt stubs based on SEEED_ARCH_MIX included frozen stubs in other mimxrt boards to improve type annotations. Signed-off-by: Jos Verlinde --- .../README.md | 1 + .../_boot.pyi | 7 + .../dht.pyi | 35 +- .../ds18x20.pyi | 26 +- .../onewire.pyi | 39 +- .../pyproject.toml | 1 + .../README.md | 1 + .../_boot.pyi | 7 + .../dht.pyi | 35 +- .../ds18x20.pyi | 26 +- .../mip/__init__.pyi | 51 +- .../onewire.pyi | 39 +- .../pyproject.toml | 3 + .../requests/__init__.pyi | 59 +- .../webrepl.pyi | 16 + .../webrepl_setup.pyi | 10 + .../LICENSE.md | 23 + .../README.md | 38 + .../__builtins__.pyi | 28 + .../_boot.pyi | 7 + .../_onewire.pyi | 15 + .../binascii.pyi | 61 + .../cmath.pyi | 84 + .../cryptolib.pyi | 165 + .../deflate.pyi | 89 + .../micropython-v1_26_1-mimxrt-stubs/dht.pyi | 15 + .../ds18x20.pyi | 16 + .../errno.pyi | 97 + .../framebuf.pyi | 247 ++ .../micropython-v1_26_1-mimxrt-stubs/gc.pyi | 112 + .../hashlib.pyi | 116 + .../heapq.pyi | 46 + .../micropython-v1_26_1-mimxrt-stubs/lwip.pyi | 51 + .../machine.pyi | 3251 +++++++++++++++++ .../micropython-v1_26_1-mimxrt-stubs/math.pyi | 269 ++ .../micropython.pyi | 346 ++ .../mimxrt.pyi | 14 + .../mip/__init__.pyi | 15 + .../network.pyi | 554 +++ .../ntptime.pyi | 5 + .../onewire.pyi | 21 + .../platform.pyi | 51 + .../pyproject.toml | 111 + .../random.pyi | 115 + .../requests/__init__.pyi | 21 + .../select.pyi | 118 + .../socket.pyi | 426 +++ .../micropython-v1_26_1-mimxrt-stubs/time.pyi | 306 ++ .../micropython-v1_26_1-mimxrt-stubs/tls.pyi | 26 + .../uarray.pyi | 2 + .../uasyncio.pyi | 2 + .../ubinascii.pyi | 2 + .../ubluetooth.pyi | 2 + .../ucollections.pyi | 15 + .../ucryptolib.pyi | 2 + .../uctypes.pyi | 164 + .../uerrno.pyi | 2 + .../uhashlib.pyi | 2 + .../uheapq.pyi | 2 + .../micropython-v1_26_1-mimxrt-stubs/uio.pyi | 2 + .../ujson.pyi | 2 + .../umachine.pyi | 2 + .../micropython-v1_26_1-mimxrt-stubs/uos.pyi | 2 + .../uplatform.pyi | 2 + .../urandom.pyi | 2 + .../micropython-v1_26_1-mimxrt-stubs/ure.pyi | 2 + .../urequests.pyi | 1 + .../uselect.pyi | 2 + .../usocket.pyi | 2 + .../micropython-v1_26_1-mimxrt-stubs/ussl.pyi | 2 + .../ustruct.pyi | 2 + .../micropython-v1_26_1-mimxrt-stubs/usys.pyi | 2 + .../utime.pyi | 2 + .../uwebsocket.pyi | 2 + .../uzlib.pyi | 2 + .../micropython-v1_26_1-mimxrt-stubs/vfs.pyi | 240 ++ .../webrepl.pyi | 16 + .../webrepl_setup.pyi | 10 + .../websocket.pyi | 17 + 79 files changed, 7527 insertions(+), 197 deletions(-) create mode 100644 publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/_boot.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/_boot.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/webrepl.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/webrepl_setup.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/LICENSE.md create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/README.md create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/__builtins__.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/_boot.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/_onewire.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/binascii.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/cmath.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/cryptolib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/deflate.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/dht.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ds18x20.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/errno.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/framebuf.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/gc.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/hashlib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/heapq.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/lwip.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/machine.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/math.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/micropython.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/mimxrt.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/mip/__init__.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/network.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ntptime.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/onewire.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/platform.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/pyproject.toml create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/random.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/requests/__init__.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/select.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/socket.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/time.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/tls.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uarray.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uasyncio.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ubinascii.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ubluetooth.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ucollections.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ucryptolib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uctypes.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uerrno.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uhashlib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uheapq.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uio.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ujson.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/umachine.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uos.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uplatform.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/urandom.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ure.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/urequests.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uselect.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/usocket.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ussl.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/ustruct.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/usys.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/utime.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uwebsocket.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/uzlib.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/vfs.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/webrepl.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/webrepl_setup.pyi create mode 100644 publish/micropython-v1_26_1-mimxrt-stubs/websocket.pyi diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/README.md b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/README.md index 72bc1b836..9f3ad04a9 100644 --- a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/README.md +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/README.md @@ -30,6 +30,7 @@ For an overview of Micropython Stubs please see: https://micropython-stubs.read Included stubs: * Merged stubs from `stubs/micropython-v1_26_1-mimxrt-MIMXRT1010_EVK-merged` +* Frozen stubs from `stubs/micropython-v1_26_1-frozen/mimxrt/GENERIC` * Core stubs from `stubs/micropython-core` diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/_boot.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/dht.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/dht.pyi index f6c87a348..7ac764e6b 100644 --- a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/dht.pyi +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/dht.pyi @@ -1,26 +1,15 @@ -""" -Module: 'dht' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK -""" - -# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} -# Stubber: v1.26.3 -from __future__ import annotations from _typeshed import Incomplete -def dht_readinto(*args, **kwargs) -> Incomplete: ... - class DHTBase: - def measure(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... - -class DHT22: - def measure(self, *args, **kwargs) -> Incomplete: ... - def temperature(self, *args, **kwargs) -> Incomplete: ... - def humidity(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... - -class DHT11: - def measure(self, *args, **kwargs) -> Incomplete: ... - def temperature(self, *args, **kwargs) -> Incomplete: ... - def humidity(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ds18x20.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ds18x20.pyi index 96f095cd9..ed17bc1b7 100644 --- a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ds18x20.pyi +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/ds18x20.pyi @@ -1,18 +1,16 @@ -""" -Module: 'ds18x20' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK -""" - -# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} -# Stubber: v1.26.3 -from __future__ import annotations from _typeshed import Incomplete +from micropython import const as const -def const(*args, **kwargs) -> Incomplete: ... +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int class DS18X20: - def read_scratch(self, *args, **kwargs) -> Incomplete: ... - def read_temp(self, *args, **kwargs) -> Incomplete: ... - def write_scratch(self, *args, **kwargs) -> Incomplete: ... - def convert_temp(self, *args, **kwargs) -> Incomplete: ... - def scan(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/onewire.pyi b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/onewire.pyi index 0f342b252..2a07804f2 100644 --- a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/onewire.pyi +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/onewire.pyi @@ -1,28 +1,21 @@ -""" -Module: 'onewire' on micropython-v1.26.1-mimxrt-MIMXRT1010_EVK -""" - -# MCU: {'variant': '', 'build': '', 'arch': 'armv7emsp', 'port': 'mimxrt', 'board': 'MIMXRT1010_EVK', 'board_id': 'MIMXRT1010_EVK', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1011DAE5A', 'version': '1.26.1'} -# Stubber: v1.26.3 -from __future__ import annotations -from typing import Final from _typeshed import Incomplete class OneWireError(Exception): ... class OneWire: - SKIP_ROM: Final[int] = 204 - SEARCH_ROM: Final[int] = 240 - MATCH_ROM: Final[int] = 85 - def select_rom(self, *args, **kwargs) -> Incomplete: ... - def writebit(self, *args, **kwargs) -> Incomplete: ... - def writebyte(self, *args, **kwargs) -> Incomplete: ... - def _search_rom(self, *args, **kwargs) -> Incomplete: ... - def write(self, *args, **kwargs) -> Incomplete: ... - def crc8(self, *args, **kwargs) -> Incomplete: ... - def readinto(self, *args, **kwargs) -> Incomplete: ... - def scan(self, *args, **kwargs) -> Incomplete: ... - def reset(self, *args, **kwargs) -> Incomplete: ... - def readbit(self, *args, **kwargs) -> Incomplete: ... - def readbyte(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/pyproject.toml b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/pyproject.toml index 998c0095d..1d7e9e7c1 100644 --- a/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/pyproject.toml +++ b/publish/micropython-v1_26_1-mimxrt-mimxrt1010_evk-stubs/pyproject.toml @@ -43,6 +43,7 @@ include = [ ] packages = [ { include = "__builtins__.pyi" }, + { include = "_boot.pyi" }, { include = "_onewire.pyi" }, { include = "binascii.pyi" }, { include = "cmath.pyi" }, diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/README.md b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/README.md index 6d13a3529..e43bb73f1 100644 --- a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/README.md +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/README.md @@ -30,6 +30,7 @@ For an overview of Micropython Stubs please see: https://micropython-stubs.read Included stubs: * Merged stubs from `stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged` +* Frozen stubs from `stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX` * Core stubs from `stubs/micropython-core` diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/_boot.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/dht.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/dht.pyi index 3a5da285f..7ac764e6b 100644 --- a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/dht.pyi +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/dht.pyi @@ -1,26 +1,15 @@ -""" -Module: 'dht' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX -""" - -# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} -# Stubber: v1.26.3 -from __future__ import annotations from _typeshed import Incomplete -def dht_readinto(*args, **kwargs) -> Incomplete: ... - class DHTBase: - def measure(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... - -class DHT22: - def measure(self, *args, **kwargs) -> Incomplete: ... - def temperature(self, *args, **kwargs) -> Incomplete: ... - def humidity(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... - -class DHT11: - def measure(self, *args, **kwargs) -> Incomplete: ... - def temperature(self, *args, **kwargs) -> Incomplete: ... - def humidity(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ds18x20.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ds18x20.pyi index cf3ac9fc2..ed17bc1b7 100644 --- a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ds18x20.pyi +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/ds18x20.pyi @@ -1,18 +1,16 @@ -""" -Module: 'ds18x20' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX -""" - -# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} -# Stubber: v1.26.3 -from __future__ import annotations from _typeshed import Incomplete +from micropython import const as const -def const(*args, **kwargs) -> Incomplete: ... +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int class DS18X20: - def read_scratch(self, *args, **kwargs) -> Incomplete: ... - def read_temp(self, *args, **kwargs) -> Incomplete: ... - def write_scratch(self, *args, **kwargs) -> Incomplete: ... - def convert_temp(self, *args, **kwargs) -> Incomplete: ... - def scan(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mip/__init__.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mip/__init__.pyi index 466c68177..773af6948 100644 --- a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mip/__init__.pyi +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/mip/__init__.pyi @@ -1,38 +1,15 @@ -""" -Module: 'mip.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX -""" -# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} -# Stubber: v1.26.3 -from __future__ import annotations -from typing import Final from _typeshed import Incomplete - -allowed_mip_url_prefixes: tuple = () -_CHUNK_SIZE: Final[int] = 128 -def _ensure_path_exists(*args, **kwargs) -> Incomplete: - ... - -def _install_json(*args, **kwargs) -> Incomplete: - ... - -def _install_package(*args, **kwargs) -> Incomplete: - ... - -def _rewrite_url(*args, **kwargs) -> Incomplete: - ... - -def install(*args, **kwargs) -> Incomplete: - ... - -def _download_file(*args, **kwargs) -> Incomplete: - ... - -def const(*args, **kwargs) -> Incomplete: - ... - -def _check_exists(*args, **kwargs) -> Incomplete: - ... - -def _chunk(*args, **kwargs) -> Incomplete: - ... - +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/onewire.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/onewire.pyi index 4994ced18..2a07804f2 100644 --- a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/onewire.pyi +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/onewire.pyi @@ -1,28 +1,21 @@ -""" -Module: 'onewire' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX -""" - -# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} -# Stubber: v1.26.3 -from __future__ import annotations -from typing import Final from _typeshed import Incomplete class OneWireError(Exception): ... class OneWire: - SKIP_ROM: Final[int] = 204 - SEARCH_ROM: Final[int] = 240 - MATCH_ROM: Final[int] = 85 - def select_rom(self, *args, **kwargs) -> Incomplete: ... - def writebit(self, *args, **kwargs) -> Incomplete: ... - def writebyte(self, *args, **kwargs) -> Incomplete: ... - def _search_rom(self, *args, **kwargs) -> Incomplete: ... - def write(self, *args, **kwargs) -> Incomplete: ... - def crc8(self, *args, **kwargs) -> Incomplete: ... - def readinto(self, *args, **kwargs) -> Incomplete: ... - def scan(self, *args, **kwargs) -> Incomplete: ... - def reset(self, *args, **kwargs) -> Incomplete: ... - def readbit(self, *args, **kwargs) -> Incomplete: ... - def readbyte(self, *args, **kwargs) -> Incomplete: ... - def __init__(self, *argv, **kwargs) -> None: ... + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/pyproject.toml b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/pyproject.toml index 1b9ac0d2c..b8247be3c 100644 --- a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/pyproject.toml +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/pyproject.toml @@ -43,6 +43,7 @@ include = [ ] packages = [ { include = "__builtins__.pyi" }, + { include = "_boot.pyi" }, { include = "_onewire.pyi" }, { include = "binascii.pyi" }, { include = "cmath.pyi" }, @@ -98,6 +99,8 @@ packages = [ { include = "uwebsocket.pyi" }, { include = "uzlib.pyi" }, { include = "vfs.pyi" }, + { include = "webrepl.pyi" }, + { include = "webrepl_setup.pyi" }, { include = "websocket.pyi" }, ] diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/requests/__init__.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/requests/__init__.pyi index 2ea7932fc..74386f89b 100644 --- a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/requests/__init__.pyi +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/requests/__init__.pyi @@ -1,42 +1,21 @@ -""" -Module: 'requests.__init__' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX -""" -# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} -# Stubber: v1.26.3 -from __future__ import annotations from _typeshed import Incomplete -def head(*args, **kwargs) -> Incomplete: - ... - -def patch(*args, **kwargs) -> Incomplete: - ... - -def post(*args, **kwargs) -> Incomplete: - ... - -def put(*args, **kwargs) -> Incomplete: - ... - -def request(*args, **kwargs) -> Incomplete: - ... - -def delete(*args, **kwargs) -> Incomplete: - ... - -def get(*args, **kwargs) -> Incomplete: - ... - - -class Response(): - def json(self, *args, **kwargs) -> Incomplete: - ... - - def close(self, *args, **kwargs) -> Incomplete: - ... - - content: Incomplete ## = - text: Incomplete ## = - def __init__(self, *argv, **kwargs) -> None: - ... - +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/webrepl.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/webrepl_setup.pyi b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-seeed_arch_mix-stubs/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/LICENSE.md b/publish/micropython-v1_26_1-mimxrt-stubs/LICENSE.md new file mode 100644 index 000000000..38a4e342c --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/LICENSE.md @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2025 Andrew Leech +Copyright (c) 2025 Jos Verlinde + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/README.md b/publish/micropython-v1_26_1-mimxrt-stubs/README.md new file mode 100644 index 000000000..932c0e3a2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/README.md @@ -0,0 +1,38 @@ +# micropython-mimxrt-stubs + + +This is a stub-only package for MicroPython. +It is intended to be installed in a projects virtual environment to allow static type checkers and intellisense features to be used while writing Micropython code. + +The version of this package is alligned the the version of the MicroPython firmware. + - Major, Minor and Patch levels are alligned to the same version as the firmware. + - The post release level is used to publish new releases of the stubs. + +For `Micropython 1.17` the stubs are published as `1.17.post1` ... `1.17.post2` +for `Micropython 1.18` the stubs are published as `1.18.post1` ... `1.18.post2` + +To install the latest stubs: +`pip install -I micropython--stubs` where port is the port of the MicroPython firmware. + +To install the stubs for an older version, such as MicroPython 1.17: +`pip install micropython-stm32-stubs==1.17.*` which will install the last post release of the stubs for MicroPython 1.17. + + +As the creation of the stubs, and merging of the different types is still going though improvements, the stub packages are marked as Beta. +To upgrade stubs to the latest stubs for a specific version use `pip install micropython-stm32-stubs==1.17.* --upgrade` + +If you have suggestions or find any issues with the stubs, please report them in the [MicroPython-stubs Discussions](https://github.com/Josverl/micropython-stubs/discussions) + +For an overview of Micropython Stubs please see: https://micropython-stubs.readthedocs.io/en/main/ + * List of all stubs : https://micropython-stubs.readthedocs.io/en/main/firmware_grp.html + + + +Included stubs: +* Merged stubs from `stubs/micropython-v1_26_1-mimxrt-SEEED_ARCH_MIX-merged` +* Frozen stubs from `stubs/micropython-v1_26_1-frozen/mimxrt/SEEED_ARCH_MIX` +* Core stubs from `stubs/micropython-core` + + +origin | Family | Port | Board | Version +-------|--------|------|-------|-------- diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/__builtins__.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/__builtins__.pyi new file mode 100644 index 000000000..5d9ece1df --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/__builtins__.pyi @@ -0,0 +1,28 @@ +"""Allows for type checking of Micropython specific builtins by pyright and pylance. +""" + +from typing import Tuple, TypeVar + +Const_T = TypeVar("Const_T", int, float, str, bytes, Tuple) # constant + +def const(expr: Const_T) -> Const_T: + """ + Used to declare that the expression is a constant so that the compiler can + optimise it. The use of this function should be as follows:: + + from micropython import const + + CONST_X = const(123) + CONST_Y = const(2 * CONST_X + 1) + + Constants declared this way are still accessible as global variables from + outside the module they are declared in. On the other hand, if a constant + begins with an underscore then it is hidden, it is not available as a global + variable, and does not take up any memory during execution. + + This `const` function is recognised directly by the MicroPython parser and is + provided as part of the :mod:`micropython` module mainly so that scripts can be + written which run under both CPython and MicroPython, by following the above + pattern. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/_boot.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/_boot.pyi new file mode 100644 index 000000000..da6e8198b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/_boot.pyi @@ -0,0 +1,7 @@ +from _typeshed import Incomplete +from machine import Pin as Pin + +bdev: Incomplete +fs: Incomplete +sdcard: Incomplete +fat: Incomplete diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/_onewire.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/_onewire.pyi new file mode 100644 index 000000000..2e9c634f3 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/_onewire.pyi @@ -0,0 +1,15 @@ +""" +Module: '_onewire' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +def reset(*args, **kwargs) -> Incomplete: ... +def writebyte(*args, **kwargs) -> Incomplete: ... +def writebit(*args, **kwargs) -> Incomplete: ... +def crc8(*args, **kwargs) -> Incomplete: ... +def readbyte(*args, **kwargs) -> Incomplete: ... +def readbit(*args, **kwargs) -> Incomplete: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/binascii.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/binascii.pyi new file mode 100644 index 000000000..3bea9ae53 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/binascii.pyi @@ -0,0 +1,61 @@ +""" +Binary/ASCII conversions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/binascii.html + +CPython module: :mod:`python:binascii` https://docs.python.org/3/library/binascii.html . + +This module implements conversions between binary data and various +encodings of it in ASCII form (in both directions). + +--- +Module: 'binascii' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any, Optional +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def crc32(data, value: Optional[Any] = None) -> Incomplete: + """ + Compute CRC-32, the 32-bit checksum of *data*, starting with an initial CRC + of *value*. The default initial CRC is zero. The algorithm is consistent + with the ZIP file checksum. + """ + ... + +def hexlify(data: bytes, sep: str | bytes = ..., /) -> bytes: + """ + Convert the bytes in the *data* object to a hexadecimal representation. + Returns a bytes object. + + If the additional argument *sep* is supplied it is used as a separator + between hexadecimal values. + """ + ... + +def unhexlify(data: str | bytes, /) -> bytes: + """ + Convert hexadecimal data to binary representation. Returns bytes string. + (i.e. inverse of hexlify) + """ + ... + +def b2a_base64(data: bytes, /) -> bytes: + """ + Encode binary data in base64 format, as in `RFC 3548 + `_. Returns the encoded data + followed by a newline character if newline is true, as a bytes object. + """ + ... + +def a2b_base64(data: str | bytes, /) -> bytes: + """ + Decode base64-encoded data, ignoring invalid characters in the input. + Conforms to `RFC 2045 s.6.8 `_. + Returns a bytes object. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/cmath.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/cmath.pyi new file mode 100644 index 000000000..a20e1eea1 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/cmath.pyi @@ -0,0 +1,84 @@ +""" +Mathematical functions for complex numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/cmath.html + +CPython module: :mod:`python:cmath` https://docs.python.org/3/library/cmath.html . + +The ``cmath`` module provides some basic mathematical functions for +working with complex numbers. + +Availability: not available on WiPy and ESP8266. Floating point support +required for this module. + +--- +Module: 'cmath' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsComplex, SupportsFloat, SupportsIndex, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_C: TypeAlias = SupportsFloat | SupportsComplex | SupportsIndex | complex + +e: float = 2.718281828459045 +"""base of the natural logarithm""" +pi: float = 3.141592653589793 +"""the ratio of a circle's circumference to its diameter""" + +def polar(z: _C, /) -> Tuple: + """ + Returns, as a tuple, the polar form of ``z``. + """ + ... + +def sqrt(z: _C, /) -> complex: + """ + Return the square-root of ``z``. + """ + ... + +def rect(r: float, phi: float, /) -> float: + """ + Returns the complex number with modulus ``r`` and phase ``phi``. + """ + ... + +def sin(z: _C, /) -> float: + """ + Return the sine of ``z``. + """ + ... + +def exp(z: _C, /) -> float: + """ + Return the exponential of ``z``. + """ + ... + +def cos(z: _C, /) -> float: + """ + Return the cosine of ``z``. + """ + ... + +def phase(z: _C, /) -> float: + """ + Returns the phase of the number ``z``, in the range (-pi, +pi]. + """ + ... + +def log(z: _C, /) -> float: + """ + Return the natural logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... + +def log10(z: _C, /) -> float: + """ + Return the base-10 logarithm of ``z``. The branch cut is along the negative real axis. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/cryptolib.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/cryptolib.pyi new file mode 100644 index 000000000..e6dd78a9d --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/cryptolib.pyi @@ -0,0 +1,165 @@ +""" +Cryptographic ciphers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/cryptolib.html + +--- +Module: 'cryptolib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +class aes: + """ + .. class:: aes + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def encrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, /) -> bytes: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def decrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None: + """ + Like `encrypt()`, but for decryption. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, IV: AnyReadableBuf, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ + + @overload + def __init__(self, key: AnyReadableBuf, mode: int, IV: AnyReadableBuf, /): + """ + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC). + * ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR). + + * *IV* is an initialization vector for CBC mode. + * For Counter mode, *IV* is the initial value for the counter. + """ diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/deflate.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/deflate.pyi new file mode 100644 index 000000000..9366f529f --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/deflate.pyi @@ -0,0 +1,89 @@ +""" +Deflate compression & decompression. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/deflate.html + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ +(commonly used in the zlib library and gzip archiver). + +**Availability:** + +* Added in MicroPython v1.21. + +* Decompression: Enabled via the ``MICROPY_PY_DEFLATE`` build option, on by default + on ports with the "extra features" level or higher (which is most boards). + +* Compression: Enabled via the ``MICROPY_PY_DEFLATE_COMPRESS`` build option, on + by default on ports with the "full features" level or higher (generally this means + you need to build your own firmware to enable this). + +--- +Module: 'deflate' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +GZIP: Final[int] = 3 +"""Supported values for the *format* parameter.""" +RAW: Final[int] = 1 +"""Supported values for the *format* parameter.""" +ZLIB: Final[int] = 2 +"""Supported values for the *format* parameter.""" +AUTO: Final[int] = 0 +"""Supported values for the *format* parameter.""" + +class DeflateIO: + """ + This class can be used to wrap a *stream* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + The *stream* must be a blocking stream. Non-blocking streams are currently + not supported. + + The *format* can be set to any of the constants defined below, and defaults + to ``AUTO`` which for decompressing will auto-detect gzip or zlib streams, + and for compressing it will generate a raw stream. + + The *wbits* parameter sets the base-2 logarithm of the DEFLATE dictionary + window size. So for example, setting *wbits* to ``10`` sets the window size + to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to + window sizes of 32 to 32k bytes). + + If *wbits* is set to ``0`` (the default), then for compression a window size + of 256 bytes will be used (as if *wbits* was set to 8). For decompression, it + depends on the format: + + * ``RAW`` will use 256 bytes (corresponding to *wbits* set to 8). + * ``ZLIB`` (or ``AUTO`` with zlib detected) will use the value from the zlib + header. + * ``GZIP`` (or ``AUTO`` with gzip detected) will use 32 kilobytes + (corresponding to *wbits* set to 15). + + See the :ref:`window size ` notes below for more information + about the window size, zlib, and gzip streams. + + If *close* is set to ``True`` then the underlying stream will be closed + automatically when the :class:`deflate.DeflateIO` stream is closed. This is + useful if you want to return a :class:`deflate.DeflateIO` stream that wraps + another stream and not have the caller need to know about managing the + underlying stream. + + If compression is enabled, a given :class:`deflate.DeflateIO` instance + supports both reading and writing. For example, a bidirectional stream like + a socket can be wrapped, which allows for compression/decompression in both + directions. + """ + def readinto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, stream, format=AUTO, wbits=0, close=False, /) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/dht.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/dht.pyi new file mode 100644 index 000000000..7ac764e6b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/dht.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete + +class DHTBase: + pin: Incomplete + buf: Incomplete + def __init__(self, pin) -> None: ... + def measure(self) -> None: ... + +class DHT11(DHTBase): + def humidity(self): ... + def temperature(self): ... + +class DHT22(DHTBase): + def humidity(self): ... + def temperature(self): ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ds18x20.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ds18x20.pyi new file mode 100644 index 000000000..ed17bc1b7 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ds18x20.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +_CONVERT: int +_RD_SCRATCH: int +_WR_SCRATCH: int + +class DS18X20: + ow: Incomplete + buf: Incomplete + def __init__(self, onewire) -> None: ... + def scan(self): ... + def convert_temp(self) -> None: ... + def read_scratch(self, rom): ... + def write_scratch(self, rom, buf) -> None: ... + def read_temp(self, rom): ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/errno.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/errno.pyi new file mode 100644 index 000000000..0a736a827 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/errno.pyi @@ -0,0 +1,97 @@ +""" +System error codes. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/errno.html + +CPython module: :mod:`python:errno` https://docs.python.org/3/library/errno.html . + +This module provides access to symbolic error codes for `OSError` exception. +A particular inventory of codes depends on :term:`MicroPython port`. + +--- +Module: 'errno' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +ENOBUFS: Final[int] = 105 +"""No buffer space available""" +ENODEV: Final[int] = 19 +"""No such device""" +ENOENT: Final[int] = 2 +"""No such file or directory""" +EISDIR: Final[int] = 21 +"""Is a directory""" +EIO: Final[int] = 5 +"""I/O error""" +EINVAL: Final[int] = 22 +"""Invalid argument""" +EPERM: Final[int] = 1 +"""Operation not permitted""" +ETIMEDOUT: Final[int] = 116 +"""Connection timed out""" +ENOMEM: Final[int] = 12 +"""Out of memory""" +EOPNOTSUPP: Final[int] = 95 +"""Operation not supported""" +ENOTCONN: Final[int] = 128 +"""Transport endpoint is not connected""" +errorcode: dict = {} +"""\ +Dictionary mapping numeric error codes to strings with symbolic error +code (see above):: + +>>> print(errno.errorcode[errno.EEXIST]) +EEXIST +""" +EAGAIN: Final[int] = 11 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EALREADY: Final[int] = 120 +"""Operation already in progress""" +EBADF: Final[int] = 9 +"""Bad file descriptor""" +EADDRINUSE: Final[int] = 112 +"""Address already in use""" +EACCES: Final[int] = 13 +"""Permission denied""" +EINPROGRESS: Final[int] = 119 +"""Operation now in progress""" +EEXIST: Final[int] = 17 +"""\ +Error codes, based on ANSI C/POSIX standard. All error codes start with +"E". As mentioned above, inventory of the codes depends on +:term:`MicroPython port`. Errors are usually accessible as ``exc.errno`` +where ``exc`` is an instance of `OSError`. Usage example:: + +try: +os.mkdir("my_dir") +except OSError as exc: +if exc.errno == errno.EEXIST: +print("Directory already exists") +""" +EHOSTUNREACH: Final[int] = 118 +"""Host is unreachable""" +ECONNABORTED: Final[int] = 113 +"""Connection aborted""" +ECONNRESET: Final[int] = 104 +"""Connection reset by peer""" +ECONNREFUSED: Final[int] = 111 +"""Connection refused""" +ENOTSUP: Final[int] = ... +"""Operation not supported""" diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/framebuf.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/framebuf.pyi new file mode 100644 index 000000000..2f57ae0e7 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/framebuf.pyi @@ -0,0 +1,247 @@ +""" +Frame buffer manipulation. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/framebuf.html + +This module provides a general frame buffer which can be used to create +bitmap images, which can then be sent to a display. + +--- +Module: 'framebuf' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Optional, Union, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +MONO_HMSB: Final[int] = 4 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +MONO_HLSB: Final[int] = 3 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are horizontally mapped. +Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. +Subsequent bytes appear at successive horizontal locations until the +rightmost edge is reached. Further bytes are rendered on the next row, one +pixel lower. +""" +RGB565: Final[int] = 1 +"""Red Green Blue (16-bit, 5+6+5) color format""" +MONO_VLSB: Final[int] = 0 +"""\ +Monochrome (1-bit) color format +This defines a mapping where the bits in a byte are vertically mapped with +bit 0 being nearest the top of the screen. Consequently each byte occupies +8 vertical pixels. Subsequent bytes appear at successive horizontal +locations until the rightmost edge is reached. Further bytes are rendered +at locations starting at the leftmost edge, 8 pixels lower. +""" +MVLSB: Final[int] = 0 +GS2_HMSB: Final[int] = 5 +"""Grayscale (2-bit) color format""" +GS8: Final[int] = 6 +"""Grayscale (8-bit) color format""" +GS4_HMSB: Final[int] = 2 +"""Grayscale (4-bit) color format""" + +def FrameBuffer1(*args, **kwargs) -> Incomplete: ... + +class FrameBuffer: + """ + The FrameBuffer class provides a pixel buffer which can be drawn upon with + pixels, lines, rectangles, text and even other FrameBuffer's. It is useful + when generating output for displays. + + For example:: + + import framebuf + + # FrameBuffer needs 2 bytes for every RGB565 pixel + fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565) + + fbuf.fill(0) + fbuf.text('MicroPython!', 0, 0, 0xffff) + fbuf.hline(0, 9, 96, 0xffff) + """ + def poly(self, x, y, coords, c, f: Union[bool, int] = False, /) -> Incomplete: + """ + Given a list of coordinates, draw an arbitrary (convex or concave) closed + polygon at the given x, y location using the given color. + + The *coords* must be specified as a :mod:`array` of integers, e.g. + ``array('h', [x0, y0, x1, y1, ... xn, yn])``. + + The optional *f* parameter can be set to ``True`` to fill the polygon. + Otherwise just a one pixel outline is drawn. + """ + ... + def vline(self, x: int, y: int, h: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + + @overload + def pixel(self, x: int, y: int, /) -> int: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + + @overload + def pixel(self, x: int, y: int, c: int, /) -> None: + """ + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + """ + def text(self, s: str, x: int, y: int, c: int = 1, /) -> None: + """ + Write text to the FrameBuffer using the coordinates as the upper-left + corner of the text. The color of the text can be defined by the optional + argument but is otherwise a default value of 1. All characters have + dimensions of 8x8 pixels and there is currently no way to change the font. + """ + ... + def rect(self, x: int, y: int, w: int, h: int, c: int, f: Union[bool, int] = False, /) -> None: + """ + Draw a rectangle at the given location, size and color. + + The optional *f* parameter can be set to ``True`` to fill the rectangle. + Otherwise just a one pixel outline is drawn. + """ + ... + def scroll(self, xstep: int, ystep: int, /) -> None: + """ + Shift the contents of the FrameBuffer by the given vector. This may + leave a footprint of the previous colors in the FrameBuffer. + """ + ... + def ellipse(self, x, y, xr, yr, c, f: Union[bool, int] = False, m: Optional[int] = None) -> None: + """ + Draw an ellipse at the given location. Radii *xr* and *yr* define the + geometry; equal values cause a circle to be drawn. The *c* parameter + defines the color. + + The optional *f* parameter can be set to ``True`` to fill the ellipse. + Otherwise just a one pixel outline is drawn. + + The optional *m* parameter enables drawing to be restricted to certain + quadrants of the ellipse. The LS four bits determine which quadrants are + to be drawn, with bit 0 specifying Q1, b1 Q2, b2 Q3 and b3 Q4. Quadrants + are numbered counterclockwise with Q1 being top right. + """ + ... + def line(self, x1: int, y1: int, x2: int, y2: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def blit( + self, + fbuf: FrameBuffer, + x: int, + y: int, + key: int = -1, + palette: Optional[bytes] = None, + /, + ) -> None: + """ + Draw another FrameBuffer on top of the current one at the given coordinates. + If *key* is specified then it should be a color integer and the + corresponding color will be considered transparent: all pixels with that + color value will not be drawn. (If the *palette* is specified then the *key* + is compared to the value from *palette*, not to the value directly from + *fbuf*.) + + *fbuf* can be another FrameBuffer instance, or a tuple or list of the form:: + + (buffer, width, height, format) + + or:: + + (buffer, width, height, format, stride) + + This matches the signature of the FrameBuffer constructor, and the elements + of the tuple/list are the same as the arguments to the constructor except that + the *buffer* here can be read-only. + + The *palette* argument enables blitting between FrameBuffers with differing + formats. Typical usage is to render a monochrome or grayscale glyph/icon to + a color display. The *palette* is a FrameBuffer instance whose format is + that of the current FrameBuffer. The *palette* height is one pixel and its + pixel width is the number of colors in the source FrameBuffer. The *palette* + for an N-bit source needs 2**N pixels; the *palette* for a monochrome source + would have 2 pixels representing background and foreground colors. The + application assigns a color to each pixel in the *palette*. The color of the + current pixel will be that of that *palette* pixel whose x position is the + color of the corresponding source pixel. + """ + ... + def hline(self, x: int, y: int, w: int, c: int, /) -> None: + """ + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + """ + ... + def fill(self, c: int, /) -> None: + """ + Fill the entire FrameBuffer with the specified color. + """ + ... + def fill_rect(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + buffer: AnyWritableBuf, + width: int, + height: int, + format: int, + stride: int = ..., + /, + ) -> None: + """ + Construct a FrameBuffer object. The parameters are: + + - *buffer* is an object with a buffer protocol which must be large + enough to contain every pixel defined by the width, height and + format of the FrameBuffer. + - *width* is the width of the FrameBuffer in pixels + - *height* is the height of the FrameBuffer in pixels + - *format* specifies the type of pixel used in the FrameBuffer; + permissible values are listed under Constants below. These set the + number of bits used to encode a color value and the layout of these + bits in *buffer*. + Where a color value c is passed to a method, c is a small integer + with an encoding that is dependent on the format of the FrameBuffer. + - *stride* is the number of pixels between each horizontal line + of pixels in the FrameBuffer. This defaults to *width* but may + need adjustments when implementing a FrameBuffer within another + larger FrameBuffer or screen. The *buffer* size must accommodate + an increased step size. + + One must specify valid *buffer*, *width*, *height*, *format* and + optionally *stride*. Invalid *buffer* size or dimensions may lead to + unexpected errors. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/gc.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/gc.pyi new file mode 100644 index 000000000..497082f3a --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/gc.pyi @@ -0,0 +1,112 @@ +""" +Control the garbage collector. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/gc.html + +CPython module: :mod:`python:gc` https://docs.python.org/3/library/gc.html . + +--- +Module: 'gc' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def mem_alloc() -> int: + """ + Return the number of bytes of heap RAM that are allocated by Python code. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +def isenabled(*args, **kwargs) -> Incomplete: ... +def mem_free() -> int: + """ + Return the number of bytes of heap RAM that is available for Python + code to allocate, or -1 if this amount is not known. + + Admonition:Difference to CPython + :class: attention + + This function is MicroPython extension. + """ + ... + +@overload +def threshold() -> int: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +@overload +def threshold(amount: int) -> None: + """ + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. + """ + +def collect() -> None: + """ + Run a garbage collection. + """ + ... + +def enable() -> None: + """ + Enable automatic garbage collection. + """ + ... + +def disable() -> None: + """ + Disable automatic garbage collection. Heap memory can still be allocated, + and garbage collection can still be initiated manually using :meth:`gc.collect`. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/hashlib.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/hashlib.pyi new file mode 100644 index 000000000..ef2d98ac0 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/hashlib.pyi @@ -0,0 +1,116 @@ +""" +Hashing algorithms. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/hashlib.html + +CPython module: :mod:`python:hashlib` https://docs.python.org/3/library/hashlib.html . + +This module implements binary data hashing algorithms. The exact inventory +of available algorithms depends on a board. Among the algorithms which may +be implemented: + +* SHA256 - The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + +* SHA1 - A previous generation algorithm. Not recommended for new usages, + but SHA1 is a part of number of Internet standards and existing + applications, so boards targeting network connectivity and + interoperability will try to provide this. + +* MD5 - A legacy algorithm, not considered cryptographically secure. Only + selected boards, targeting interoperability with legacy applications, + will offer this. + +--- +Module: 'hashlib' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, _Hash +from typing import NoReturn, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated + +class sha1(_Hash): + """ + A previous generation algorithm. Not recommended for new usages, + but SHA1 is a part of number of Internet standards and existing + applications, so boards targeting network connectivity and + interoperability will try to provide this. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA1 hasher object and optionally feed ``data`` into it. + """ + +class sha256(_Hash): + """ + The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + + @overload + def __init__(self, data: AnyReadableBuf): + """ + Create an SHA256 hasher object and optionally feed ``data`` into it. + """ + +class md5(_Hash): + """ + A legacy algorithm, not considered cryptographically secure. Only + selected boards, targeting interoperability with legacy applications, + will offer this. + """ + def digest(self, *args, **kwargs) -> Incomplete: ... + def update(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, data: AnyReadableBuf = ..., /) -> None: + """ + Create an MD5 hasher object and optionally feed ``data`` into it. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/heapq.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/heapq.pyi new file mode 100644 index 000000000..e861ff86b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/heapq.pyi @@ -0,0 +1,46 @@ +""" +Heap queue algorithm. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/heapq.html + +CPython module: :mod:`python:heapq` https://docs.python.org/3/library/heapq.html . + +This module implements the +`min heap queue algorithm `_. + +A heap queue is essentially a list that has its elements stored in such a way +that the first item of the list is always the smallest. + +--- +Module: 'heapq' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Any +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +def heappop(heap: list[_T], /) -> _T: + """ + Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if + ``heap`` is empty. + + The returned item will be the smallest item in the ``heap``. + """ + ... + +def heappush(heap: list[_T], item: _T, /) -> None: + """ + Push the ``item`` onto the ``heap``. + """ + ... + +def heapify(x: list[Any], /) -> None: + """ + Convert the list ``x`` into a heap. This is an in-place operation. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/lwip.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/lwip.pyi new file mode 100644 index 000000000..74afeef79 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/lwip.pyi @@ -0,0 +1,51 @@ +""" +Module: 'lwip' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +SOCK_RAW: Final[int] = 3 +SOCK_STREAM: Final[int] = 1 +SOCK_DGRAM: Final[int] = 2 +MSG_PEEK: Final[int] = 1 +SO_REUSEADDR: Final[int] = 4 +SOL_SOCKET: Final[int] = 1 +SO_BROADCAST: Final[int] = 32 +TCP_NODELAY: Final[int] = 64 +AF_INET6: Final[int] = 10 +IPPROTO_IP: Final[int] = 0 +AF_INET: Final[int] = 2 +MSG_DONTWAIT: Final[int] = 2 +IP_DROP_MEMBERSHIP: Final[int] = 1025 +IPPROTO_TCP: Final[int] = 6 +IP_ADD_MEMBERSHIP: Final[int] = 1024 + +def reset(*args, **kwargs) -> Incomplete: ... +def print_pcbs(*args, **kwargs) -> Incomplete: ... +def getaddrinfo(*args, **kwargs) -> Incomplete: ... +def callback(*args, **kwargs) -> Incomplete: ... + +class socket: + def recvfrom(self, *args, **kwargs) -> Incomplete: ... + def recv(self, *args, **kwargs) -> Incomplete: ... + def makefile(self, *args, **kwargs) -> Incomplete: ... + def listen(self, *args, **kwargs) -> Incomplete: ... + def settimeout(self, *args, **kwargs) -> Incomplete: ... + def sendall(self, *args, **kwargs) -> Incomplete: ... + def setsockopt(self, *args, **kwargs) -> Incomplete: ... + def setblocking(self, *args, **kwargs) -> Incomplete: ... + def sendto(self, *args, **kwargs) -> Incomplete: ... + def readline(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def connect(self, *args, **kwargs) -> Incomplete: ... + def send(self, *args, **kwargs) -> Incomplete: ... + def bind(self, *args, **kwargs) -> Incomplete: ... + def accept(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/machine.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/machine.pyi new file mode 100644 index 000000000..b16f2ce44 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/machine.pyi @@ -0,0 +1,3251 @@ +""" +Functions related to the hardware. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/machine.html + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. + +--- +Module: 'machine' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import NoReturn, Union, Tuple, Callable, List, Sequence, Any, Optional, overload, Final +from _typeshed import Incomplete +from _mpy_shed import _IRQ, AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar, deprecated +from vfs import AbstractBlockDev + +SOFT_RESET: Final[int] = 5 +"""Reset causes.""" +PWRON_RESET: Final[int] = 1 +"""Reset causes.""" +WDT_RESET: Final[int] = 3 +"""Reset causes.""" +ATTN_0DB: int = ... +ID_T: TypeAlias = int | str +PinLike: TypeAlias = Pin | int | str +IDLE: Incomplete +"""IRQ wake values.""" +SLEEP: Incomplete +"""IRQ wake values.""" +DEEPSLEEP: Incomplete +"""IRQ wake values.""" +HARD_RESET: Incomplete +"""Reset causes.""" +DEEPSLEEP_RESET: Incomplete +"""Reset causes.""" +WLAN_WAKE: Incomplete +"""Wake-up reasons.""" +PIN_WAKE: Incomplete +"""Wake-up reasons.""" +RTC_WAKE: Incomplete +"""Wake-up reasons.""" +_IRQ_STATE: TypeAlias = int + +def unique_id() -> bytes: + """ + Returns a byte string with a unique identifier of a board/SoC. It will vary + from a board/SoC instance to another, if underlying hardware allows. Length + varies by hardware (so use substring of a full value if you expect a short + ID). In some MicroPython ports, ID corresponds to the network MAC address. + """ + ... + +def disable_irq() -> _IRQ_STATE: + """ + Disable interrupt requests. + Returns the previous IRQ state which should be considered an opaque value. + This return value should be passed to the `enable_irq()` function to restore + interrupts to their original state, before `disable_irq()` was called. + """ + ... + +def dht_readinto(*args, **kwargs) -> Incomplete: ... +def bitstream(pin, encoding, timing, data, /) -> Incomplete: + """ + Transmits *data* by bit-banging the specified *pin*. The *encoding* argument + specifies how the bits are encoded, and *timing* is an encoding-specific timing + specification. + + The supported encodings are: + + - ``0`` for "high low" pulse duration modulation. This will transmit 0 and + 1 bits as timed pulses, starting with the most significant bit. + The *timing* must be a four-tuple of nanoseconds in the format + ``(high_time_0, low_time_0, high_time_1, low_time_1)``. For example, + ``(400, 850, 800, 450)`` is the timing specification for WS2812 RGB LEDs + at 800kHz. + + The accuracy of the timing varies between ports. On Cortex M0 at 48MHz, it is + at best +/- 120ns, however on faster MCUs (ESP8266, ESP32, STM32, Pyboard), it + will be closer to +/-30ns. + + ``Note:`` For controlling WS2812 / NeoPixel strips, see the :mod:`neopixel` + module for a higher-level API. + """ + ... + +def bootloader(value: Optional[Any] = None) -> None: + """ + Reset the device and enter its bootloader. This is typically used to put the + device into a state where it can be programmed with new firmware. + + Some ports support passing in an optional *value* argument which can control + which bootloader to enter, what to pass to it, or other things. + """ + ... + +@overload +def deepsleep() -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def deepsleep(time_ms: int, /) -> NoReturn: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +def enable_irq(state: _IRQ_STATE, /) -> None: + """ + Re-enable interrupt requests. + The *state* parameter should be the value that was returned from the most + recent call to the `disable_irq()` function. + """ + ... + +def reset_cause() -> int: + """ + Get the reset cause. See :ref:`constants ` for the possible return values. + """ + ... + +def soft_reset() -> NoReturn: + """ + Performs a :ref:`soft reset ` of the interpreter, deleting all + Python objects and resetting the Python heap. + """ + ... + +def time_pulse_us(pin: Pin, pulse_level: int, timeout_us: int = 1_000_000, /) -> int: + """ + Time a pulse on the given *pin*, and return the duration of the pulse in + microseconds. The *pulse_level* argument should be 0 to time a low pulse + or 1 to time a high pulse. + + If the current input value of the pin is different to *pulse_level*, + the function first (*) waits until the pin input becomes equal to *pulse_level*, + then (**) times the duration that the pin is equal to *pulse_level*. + If the pin is already equal to *pulse_level* then timing starts straight away. + + The function will return -2 if there was timeout waiting for condition marked + (*) above, and -1 if there was timeout during the main measurement, marked (**) + above. The timeout is the same for both cases and given by *timeout_us* (which + is in microseconds). + """ + ... + +def reset() -> NoReturn: + """ + :ref:`Hard resets ` the device in a manner similar to pushing the + external RESET button. + """ + ... + +@overload +def freq() -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(hz: int, /) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq(self) -> int: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +@overload +def freq( + self, + value: int, + /, +) -> None: + """ + Returns the CPU frequency in hertz. + + On some ports this can also be used to set the CPU frequency by passing in *hz*. + """ + +def idle() -> None: + """ + Gates the clock to the CPU, useful to reduce power consumption at any time + during short or long periods. Peripherals continue working and execution + resumes as soon as any interrupt is triggered, or at most one millisecond + after the CPU was paused. + + It is recommended to call this function inside any tight loop that is + continuously checking for an external change (i.e. polling). This will reduce + power consumption without significantly impacting performance. To reduce + power consumption further then see the :func:`lightsleep`, + :func:`time.sleep()` and :func:`time.sleep_ms()` functions. + """ + ... + +@overload +def lightsleep() -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +@overload +def lightsleep(time_ms: int, /) -> None: + """ + Stops execution in an attempt to enter a low power state. + + If *time_ms* is specified then this will be the maximum time in milliseconds that + the sleep will last for. Otherwise the sleep can last indefinitely. + + With or without a timeout, execution may resume at any time if there are events + that require processing. Such events, or wake sources, should be configured before + sleeping, like `Pin` change or `RTC` timeout. + + The precise behaviour and power-saving capabilities of lightsleep and deepsleep is + highly dependent on the underlying hardware, but the general properties are: + + * A lightsleep has full RAM and state retention. Upon wake execution is resumed + from the point where the sleep was requested, with all subsystems operational. + + * A deepsleep may not retain RAM or any other state of the system (for example + peripherals or network interfaces). Upon wake execution is resumed from the main + script, similar to a hard or power-on reset. The `reset_cause()` function will + return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake + from other resets. + """ + +mem8: Incomplete ## = <8-bit memory> +"""Read/write 8 bits of memory.""" +mem32: Incomplete ## = <32-bit memory> +"""\ +Read/write 32 bits of memory. + +Use subscript notation ``[...]`` to index these objects with the address of +interest. Note that the address is the byte address, regardless of the size of +memory being accessed. + +Example use (registers are specific to an stm32 microcontroller): +""" +mem16: Incomplete ## = <16-bit memory> +"""Read/write 16 bits of memory.""" + +class LED: + def on(self, *args, **kwargs) -> Incomplete: ... + def toggle(self, *args, **kwargs) -> Incomplete: ... + def off(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class PWM: + """ + This class provides pulse width modulation output. + + Example usage:: + + from machine import PWM + + pwm = PWM(pin) # create a PWM object on a pin + pwm.duty_u16(32768) # set duty to 50% + + # reinitialise with a period of 200us, duty of 5us + pwm.init(freq=5000, duty_ns=5000) + + pwm.duty_ns(3000) # set pulse width to 3us + + pwm.deinit() + + + Limitations of PWM + ------------------ + + * Not all frequencies can be generated with absolute accuracy due to + the discrete nature of the computing hardware. Typically the PWM frequency + is obtained by dividing some integer base frequency by an integer divider. + For example, if the base frequency is 80MHz and the required PWM frequency is + 300kHz the divider must be a non-integer number 80000000 / 300000 = 266.67. + After rounding the divider is set to 267 and the PWM frequency will be + 80000000 / 267 = 299625.5 Hz, not 300kHz. If the divider is set to 266 then + the PWM frequency will be 80000000 / 266 = 300751.9 Hz, but again not 300kHz. + + * The duty cycle has the same discrete nature and its absolute accuracy is not + achievable. On most hardware platforms the duty will be applied at the next + frequency period. Therefore, you should wait more than "1/frequency" before + measuring the duty. + + * The frequency and the duty cycle resolution are usually interdependent. + The higher the PWM frequency the lower the duty resolution which is available, + and vice versa. For example, a 300kHz PWM frequency can have a duty cycle + resolution of 8 bit, not 16-bit as may be expected. In this case, the lowest + 8 bits of *duty_u16* are insignificant. So:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2) + + and:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255) + + will generate PWM with the same 50% duty cycle. + """ + + @overload + def duty_u16(self) -> int: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def duty_u16( + self, + value: int, + /, + ) -> None: + """ + Get or set the current duty cycle of the PWM output, as an unsigned 16-bit + value in the range 0 to 65535 inclusive. + + With no arguments the duty cycle is returned. + + With a single *value* argument the duty cycle is set to that value, measured + as the ratio ``value / 65535``. + """ + + @overload + def freq(self) -> int: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + + @overload + def freq( + self, + value: int, + /, + ) -> None: + """ + Get or set the current frequency of the PWM output. + + With no arguments the frequency in Hz is returned. + + With a single *value* argument the frequency is set to that value in Hz. The + method may raise a ``ValueError`` if the frequency is outside the valid range. + """ + def init(self, *, freq: int = ..., duty_u16: int = ..., duty_ns: int = ...) -> None: + """ + Modify settings for the PWM object. See the above constructor for details + about the parameters. + """ + ... + + @overload + def duty_ns(self) -> int: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + + @overload + def duty_ns( + self, + value: int, + /, + ) -> None: + """ + Get or set the current pulse width of the PWM output, as a value in nanoseconds. + + With no arguments the pulse width in nanoseconds is returned. + + With a single *value* argument the pulse width is set to that value. + """ + def deinit(self) -> None: + """ + Disable the PWM output. + """ + ... + def __init__( + self, + dest: PinLike, + /, + *, + freq: int = ..., + duty_u16: int = ..., + duty_ns: int = ..., + ) -> None: + """ + Construct and return a new PWM object using the following parameters: + + - *dest* is the entity on which the PWM is output, which is usually a + :ref:`machine.Pin ` object, but a port may allow other values, + like integers. + - *freq* should be an integer which sets the frequency in Hz for the + PWM cycle. + - *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``. + - *duty_ns* sets the pulse width in nanoseconds. + + Setting *freq* may affect other PWM objects if the objects share the same + underlying PWM generator (this is hardware specific). + Only one of *duty_u16* and *duty_ns* should be specified at a time. + """ + +class I2S: + """ + I2S is a synchronous serial protocol used to connect digital audio devices. + At the physical level, a bus consists of 3 lines: SCK, WS, SD. + The I2S class supports controller operation. Peripheral operation is not supported. + + The I2S class is currently available as a Technical Preview. During the preview period, feedback from + users is encouraged. Based on this feedback, the I2S class API and implementation may be changed. + + I2S objects can be created and initialized using:: + + from machine import I2S + from machine import Pin + + # ESP32 + sck_pin = Pin(14) # Serial clock output + ws_pin = Pin(13) # Word clock output + sd_pin = Pin(12) # Serial data output + + or + + # PyBoards + sck_pin = Pin("Y6") # Serial clock output + ws_pin = Pin("Y5") # Word clock output + sd_pin = Pin("Y8") # Serial data output + + audio_out = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.TX, + bits=16, + format=I2S.MONO, + rate=44100, + ibuf=20000) + + audio_in = I2S(2, + sck=sck_pin, ws=ws_pin, sd=sd_pin, + mode=I2S.RX, + bits=32, + format=I2S.STEREO, + rate=22050, + ibuf=20000) + + 3 modes of operation are supported: + - blocking + - non-blocking + - uasyncio + + blocking:: + + num_written = audio_out.write(buf) # blocks until buf emptied + + num_read = audio_in.readinto(buf) # blocks until buf filled + + non-blocking:: + + audio_out.irq(i2s_callback) # i2s_callback is called when buf is emptied + num_written = audio_out.write(buf) # returns immediately + + audio_in.irq(i2s_callback) # i2s_callback is called when buf is filled + num_read = audio_in.readinto(buf) # returns immediately + + uasyncio:: + + swriter = uasyncio.StreamWriter(audio_out) + swriter.write(buf) + await swriter.drain() + + sreader = uasyncio.StreamReader(audio_in) + num_read = await sreader.readinto(buf) + """ + + RX: Final[int] = 0 + """for initialising the I2S bus ``mode`` to receive""" + MONO: Final[int] = 0 + """for initialising the I2S bus ``format`` to mono""" + STEREO: Final[int] = 1 + """for initialising the I2S bus ``format`` to stereo""" + TX: Final[int] = 1 + """for initialising the I2S bus ``mode`` to transmit""" + @staticmethod + def shift( + buf: AnyWritableBuf, + bits: int, + shift: int, + /, + ) -> None: + """ + bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample. + Positive for left shift, negative for right shift. + Typically used for volume control. Each bit shift changes sample volume by 6dB. + """ + ... + def init( + self, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + see Constructor for argument descriptions + """ + ... + def irq( + self, + handler: Callable[[Any], None], + /, + ) -> None: + """ + Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method). + Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation. + ``handler`` is called in the context of the MicroPython scheduler. + """ + ... + def readinto( + self, + buf: AnyWritableBuf, + /, + ) -> int: + """ + Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the left channel sample data is used. + Returns number of bytes read + """ + ... + def deinit(self) -> None: + """ + Deinitialize the I2S bus + """ + ... + def write( + self, + buf: AnyReadableBuf, + /, + ) -> int: + """ + Write audio samples contained in ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + the sample data is written to both the right and left channels. + Returns number of bytes written + """ + ... + def __init__( + self, + id: ID_T, + /, + *, + sck: PinLike, + ws: PinLike, + sd: PinLike, + mode: int, + bits: int, + format: int, + rate: int, + ibuf: int, + ) -> None: + """ + Construct an I2S object of the given id: + + - ``id`` identifies a particular I2S bus. + + ``id`` is board and port specific: + + - PYBv1.0/v1.1: has one I2S bus with id=2. + - PYBD-SFxW: has two I2S buses with id=1 and id=2. + - ESP32: has two I2S buses with id=0 and id=1. + + Keyword-only parameters that are supported on all ports: + + - ``sck`` is a pin object for the serial clock line + - ``ws`` is a pin object for the word select line + - ``sd`` is a pin object for the serial data line + - ``mode`` specifies receive or transmit + - ``bits`` specifies sample size (bits), 16 or 32 + - ``format`` specifies channel format, STEREO or MONO + - ``rate`` specifies audio sampling rate (samples/s) + - ``ibuf`` specifies internal buffer length (bytes) + + For all ports, DMA runs continuously in the background and allows user applications to perform other operations while + sample data is transfered between the internal buffer and the I2S peripheral unit. + Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations + before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method). + """ + +class ADC: + """ + The ADC class provides an interface to analog-to-digital convertors, and + represents a single endpoint that can sample a continuous voltage and + convert it to a discretised value. + + Example usage:: + + import machine + + adc = machine.ADC(pin) # create an ADC object acting on a pin + val = adc.read_u16() # read a raw analog value in the range 0-65535 + """ + + VREF: int = ... + CORE_VREF: int = ... + CORE_VBAT: int = ... + CORE_TEMP: int = ... + ATTN_0DB: int = 0 + ATTN_2_5DB: int = 1 + ATTN_6DB: int = 2 + ATTN_11DB: int = 3 + WIDTH_9BIT: int = 9 + WIDTH_10BIT: int = 10 + WIDTH_11BIT: int = 11 + WIDTH_12BIT: int = 12 + def read_uv(self) -> int: + """ + Take an analog reading and return an integer value with units of + microvolts. It is up to the particular port whether or not this value + is calibrated, and how calibration is done. + """ + ... + def read_u16(self) -> int: + """ + Take an analog reading and return an integer in the range 0-65535. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 65535. + """ + ... + def __init__(self, pin: PinLike, *, atten=ATTN_0DB) -> None: + """ + Access the ADC associated with a source identified by *id*. This + *id* may be an integer (usually specifying a channel number), a + :ref:`Pin ` object, or other value supported by the + underlying machine. + .. note:: + + WiPy has a custom implementation of ADC, see ADCWiPy for details. + + on ESP32 : `atten` specifies the attenuation level for the ADC input. + """ + + # ESP32 specific + @mp_available(port="esp32") + @deprecated("Use ADC.block().init(bits=bits) instead.") + def width(self, bits: int) -> None: + """ + Equivalent to ADC.block().init(bits=bits). + The only chip that can switch resolution to a lower one is the normal esp32. The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits. + + For compatibility, the ADC object also provides constants matching the supported ADC resolutions, per chip: + + ESP32: + ADC.WIDTH_9BIT = 9 + ADC.WIDTH_10BIT = 10 + ADC.WIDTH_11BIT = 11 + ADC.WIDTH_12BIT = 12 + + ESP32 C3 & S3: + ADC.WIDTH_12BIT = 12 + + ESP32 S2: + ADC.WIDTH_13BIT = 13 + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use read_u16() instead.") + def read(self) -> int: + """ + Take an analog reading and return an integer in the range 0-4095. + The return value represents the raw reading taken by the ADC, scaled + such that the minimum value is 0 and the maximum value is 4095. + + This method is deprecated, use `read_u16()` instead. + + Available : ESP32 + """ + ... + + @mp_available(port="esp32") + @deprecated("Use ADC.init(atten=atten) instead.") + def atten(self, atten: int) -> None: + """ + Set the attenuation level for the ADC input. + + Available : ESP32 + """ + ... + +class I2C: + """ + 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. + + I2C objects are created attached to a specific bus. They can be initialised + when created, or initialised later on. + + Printing the I2C object gives you information about its configuration. + + Both hardware and software I2C implementations exist via the + :ref:`machine.I2C ` and `machine.SoftI2C` classes. Hardware I2C uses + underlying hardware support of the system to perform the reads/writes and is + usually efficient and fast but may have restrictions on which pins can be used. + Software I2C is implemented by bit-banging and can be used on any pin but is not + as efficient. These classes have the same methods available and differ primarily + in the way they are constructed. + + Example usage:: + + from machine import I2C + + i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz + # depending on the port, extra parameters may be required + # to select the peripheral and/or pins to use + + i2c.scan() # scan for peripherals, returning a list of 7-bit addresses + + i2c.writeto(42, b'123') # write 3 bytes to peripheral with 7-bit address 42 + i2c.readfrom(42, 4) # read 4 bytes from peripheral with 7-bit address 42 + + i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of peripheral 42, + # starting at memory-address 8 in the peripheral + i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42 + # starting at address 2 in the peripheral + """ + def readfrom_mem_into(self, addr: int, memaddr: int, buf: AnyWritableBuf, /, *, addrsize: int = 8) -> None: + """ + Read into *buf* from the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. The number of bytes read is the + length of *buf*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def readfrom_into(self, addr: int, buf: AnyWritableBuf, stop: bool = True, /) -> None: + """ + Read into *buf* from the peripheral specified by *addr*. + The number of bytes read will be the length of *buf*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + + The method returns ``None``. + """ + ... + def readfrom_mem(self, addr: int, memaddr: int, nbytes: int, /, *, addrsize: int = 8) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr* starting from the memory + address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits. + Returns a `bytes` object with the data read. + """ + ... + def writeto_mem(self, addr: int, memaddr: int, buf: AnyReadableBuf, /, *, addrsize: int = 8) -> None: + """ + Write *buf* to the peripheral specified by *addr* starting from the + memory address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + """ + ... + def scan(self) -> List: + """ + 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 write bit) is sent on the bus. + """ + ... + def writeto(self, addr: int, buf: AnyReadableBuf, stop: bool = True, /) -> int: + """ + Write the bytes from *buf* to the peripheral specified by *addr*. If a + NACK is received following the write of a byte from *buf* then the + remaining bytes are not sent. If *stop* is true then a STOP condition is + generated at the end of the transfer, even if a NACK is received. + The function returns the number of ACKs that were received. + """ + ... + def writevto(self, addr: int, vector: Sequence[AnyReadableBuf], stop: bool = True, /) -> int: + """ + Write the bytes contained in *vector* to the peripheral specified by *addr*. + *vector* should be a tuple or list of objects with the buffer protocol. + The *addr* is sent once and then the bytes from each object in *vector* + are written out sequentially. The objects in *vector* may be zero bytes + in length in which case they don't contribute to the output. + + If a NACK is received following the write of a byte from one of the + objects in *vector* then the remaining bytes, and any remaining objects, + are not sent. If *stop* is true then a STOP condition is generated at + the end of the transfer, even if a NACK is received. The function + returns the number of ACKs that were received. + """ + ... + def start(self) -> None: + """ + Generate a START condition on the bus (SDA transitions to low while SCL is high). + """ + ... + def readfrom(self, addr: int, nbytes: int, stop: bool = True, /) -> bytes: + """ + Read *nbytes* from the peripheral specified by *addr*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + Returns a `bytes` object with the data read. + """ + ... + def readinto(self, buf: AnyWritableBuf, nack: bool = True, /) -> None: + """ + Reads bytes from the bus and stores them into *buf*. The number of bytes + read is the length of *buf*. An ACK will be sent on the bus after + receiving all but the last byte. After the last byte is received, if *nack* + is true then a NACK will be sent, otherwise an ACK will be sent (and in this + case the peripheral assumes more bytes are going to be read in a later call). + """ + ... + + @overload + def init(self, *, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + + @overload + def init(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + def stop(self) -> None: + """ + Generate a STOP condition on the bus (SDA transitions to high while SCL is high). + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes from *buf* to the bus. Checks that an ACK is received + after each byte and stops transmitting the remaining bytes if a NACK is + received. The function returns the number of ACKs that were received. + """ + ... + + @overload + def __init__(self, id: ID_T, /, *, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, id: ID_T, /, *, scl: PinLike, sda: PinLike, freq: int = 400_000): + """ + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values for + depend on the particular port/board + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + @overload + def __init__(self, *, scl: PinLike, sda: PinLike, freq: int = 400_000) -> None: + """ + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + """ + +class I2CTarget: + """ + Construct and return a new I2CTarget object using the following parameters: + + - *id* identifies a particular I2C peripheral. Allowed values depend on the + particular port/board. Some ports have a default in which case this parameter + can be omitted. + - *addr* is the I2C address of the target. + - *addrsize* is the number of bits in the I2C target address. Valid values + are 7 and 10. + - *mem* is an object with the buffer protocol that is writable. If not + specified then there is no backing memory and data must be read/written + using the :meth:`I2CTarget.readinto` and :meth:`I2CTarget.write` methods. + - *mem_addrsize* is the number of bits in the memory address. Valid values + are 0, 8, 16, 24 and 32. + - *scl* is a pin object specifying the pin to use for SCL. + - *sda* is a pin object specifying the pin to use for SDA. + + Note that some ports/boards will have default values of *scl* and *sda* + that can be changed in this constructor. Others will have fixed values + of *scl* and *sda* that cannot be changed. + """ + + IRQ_END_READ: Final[int] = 16 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_WRITE: Final[int] = 2 + """IRQ trigger sources.""" + IRQ_END_WRITE: Final[int] = 32 + """IRQ trigger sources.""" + IRQ_READ_REQ: Final[int] = 4 + """IRQ trigger sources.""" + IRQ_ADDR_MATCH_READ: Final[int] = 1 + """IRQ trigger sources.""" + IRQ_WRITE_REQ: Final[int] = 8 + """IRQ trigger sources.""" + def deinit(self) -> Incomplete: + """ + Deinitialise the I2C target. After this method is called the hardware will no + longer respond to requests on the I2C bus, and no other methods can be called. + """ + ... + def irq(self, handler=None, trigger=IRQ_END_READ | IRQ_END_WRITE, hard=False) -> Incomplete: + """ + Configure an IRQ *handler* to be called when an event occurs. The possible events are + given by the following constants, which can be or'd together and passed to the *trigger* + argument: + + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a read transaction. + - ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a + controller for a write transaction. + - ``IRQ_READ_REQ`` indicates that the controller is requesting data, and this + request must be satisfied by calling `I2CTarget.write` with the data to be + passed back to the controller. + - ``IRQ_WRITE_REQ`` indicates that the controller has written data, and the + data must be read by calling `I2CTarget.readinto`. + - ``IRQ_END_READ`` indicates that the controller has finished a read transaction. + - ``IRQ_END_WRITE`` indicates that the controller has finished a write transaction. + + Not all triggers are available on all ports. If a port has the constant then that + event is available. + + Note the following restrictions: + + - ``IRQ_ADDR_MATCH_READ``, ``IRQ_ADDR_MATCH_READ``, ``IRQ_READ_REQ`` and + ``IRQ_WRITE_REQ`` must be handled by a hard IRQ callback (with the *hard* argument + set to ``True``). This is because these events have very strict timing requirements + and must usually be satisfied synchronously with the hardware event. + + - ``IRQ_END_READ`` and ``IRQ_END_WRITE`` may be handled by either a soft or hard + IRQ callback (although note that all events must be registered with the same handler, + so if any events need a hard callback then all events must be hard). + + - If a memory buffer has been supplied in the constructor then ``IRQ_END_WRITE`` + is not emitted for the transaction that writes the memory address. This is to + allow ``IRQ_END_READ`` and ``IRQ_END_WRITE`` to function correctly as soft IRQ + callbacks, where the IRQ handler may be called quite some time after the actual + hardware event. + """ + ... + def write(self, buf) -> int: + """ + Write out the bytes from the given buffer, to be passed to the I2C controller + after it sends a read request. Returns the number of bytes written. Most ports + only accept one byte at a time to this method. + """ + ... + def readinto(self, buf) -> int: + """ + Read into the given buffer any pending bytes written by the I2C controller. + Returns the number of bytes read. + """ + ... + def __init__(self, id, addr, *, addrsize=7, mem=None, mem_addrsize=8, scl=None, sda=None) -> None: ... + +class UART: + """ + UART implements the standard UART/USART duplex serial communications protocol. At + the physical level it consists of 2 lines: RX and TX. The unit of communication + is a character (not to be confused with a string character) which can be 8 or 9 + bits wide. + + UART objects can be created and initialised using:: + + from machine import UART + + uart = UART(1, 9600) # init with given baudrate + uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters + + Supported parameters differ on a board: + + Pyboard: Bits can be 7, 8 or 9. Stop can be 1 or 2. With *parity=None*, + only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits + are supported. + + WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2. + + A UART object acts like a `stream` object and reading and writing is done + using the standard stream methods:: + + uart.read(10) # read 10 characters, returns a bytes object + uart.read() # read all available characters + uart.readline() # read a line + uart.readinto(buf) # read and store into the given buffer + uart.write('abc') # write the 3 characters + """ + + INV_TX: Final[int] = 1 + INV_RX: Final[int] = 2 + CTS: Final[int] = 2 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RXIDLE: Final[int] = 1 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + IRQ_TXIDLE: Final[int] = 2 + """\ + IRQ trigger sources. + + Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200. + """ + RTS: Final[int] = 1 + """\ + Flow control options. + + Availability: esp32, mimxrt, renesas-ra, rp2, stm32. + """ + IRQ_RX: Incomplete + IRQ_BREAK: Incomplete + IDLE: int = ... + def irq( + self, + handler: Callable[[UART], None] | None = None, + trigger: int = 0, + hard: bool = False, + /, + ) -> _IRQ: + """ + Configure an interrupt handler to be called when a UART event occurs. + + The arguments are: + + - *handler* is an optional function to be called when the interrupt event + triggers. The handler must take exactly one argument which is the + ``UART`` instance. + + - *trigger* configures the event(s) which can generate an interrupt. + Possible values are a mask of one or more of the following: + + - ``UART.IRQ_RXIDLE`` interrupt after receiving at least one character + and then the RX line goes idle. + - ``UART.IRQ_RX`` interrupt after each received character. + - ``UART.IRQ_TXIDLE`` interrupt after or while the last character(s) of + a message are or have been sent. + - ``UART.IRQ_BREAK`` interrupt when a break state is detected at RX + + - *hard* if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + + Returns an irq object. + + Due to limitations of the hardware not all trigger events are available on all ports. + """ + ... + def sendbreak(self) -> None: + """ + Send a break condition on the bus. This drives the bus low for a duration + longer than required for a normal transmission of a character. + """ + ... + def deinit(self) -> None: + """ + Turn off the UART bus. + + .. note:: + You will not be able to call ``init()`` on the object after ``deinit()``. + A new instance needs to be created in that case. + """ + ... + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + + @overload + def init( + self, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *rts* specifies the RTS (output) pin to use for hardware receive flow control. + - *cts* specifies the CTS (input) pin to use for hardware transmit flow control. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + - *timeout* specifies the time to wait for the first character (in ms). + - *timeout_char* specifies the time to wait between characters (in ms). + - *invert* specifies which lines to invert. + + - ``0`` will not invert lines (idle state of both lines is logic high). + - ``UART.INV_TX`` will invert TX line (idle state of TX line now logic low). + - ``UART.INV_RX`` will invert RX line (idle state of RX line now logic low). + - ``UART.INV_TX | UART.INV_RX`` will invert both lines (idle state at logic low). + + - *flow* specifies which hardware flow control signals to use. The value + is a bitmask. + + - ``0`` will ignore hardware flow control signals. + - ``UART.RTS`` will enable receive flow control by using the RTS output pin to + signal if the receive FIFO has sufficient space to accept more data. + - ``UART.CTS`` will enable transmit flow control by pausing transmission when the + CTS input pin signals that the receiver is running low on buffer space. + - ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + + .. note:: + It is possible to call ``init()`` multiple times on the same object in + order to reconfigure UART on the fly. That allows using single UART + peripheral to serve different devices attached to different GPIO pins. + Only one device can be served at a time in that case. + Also do not call ``deinit()`` as it will prevent calling ``init()`` + again. + """ + def flush(self) -> Incomplete: + """ + Waits until all data has been sent. In case of a timeout, an exception is raised. The timeout + duration depends on the tx buffer size and the baud rate. Unless flow control is enabled, a timeout + should not occur. + + .. note:: + + For the esp8266 and nrf ports the call returns while the last byte is sent. + If required, a one character wait time has to be added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + def txdone(self) -> bool: + """ + Tells whether all data has been sent or no data transfer is happening. In this case, + it returns ``True``. If a data transmission is ongoing it returns ``False``. + + .. note:: + + For the esp8266 and nrf ports the call may return ``True`` even if the last byte + of a transfer is still being sent. If required, a one character wait time has to be + added in the calling script. + + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra + """ + ... + + @overload + def read(self) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + + @overload + def read(self, nbytes: int, /) -> bytes | None: + """ + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + """ + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read without + blocking. It will return 0 if there are no characters available and a positive + number if there are characters. The method may return 1 even if there is more + than one character available for reading. + + For more sophisticated querying of available characters use select.poll:: + + poll = select.poll() + poll.register(uart, select.POLLIN) + poll.poll(timeout) + """ + ... + def write(self, buf: AnyReadableBuf, /) -> Union[int, None]: + """ + Write the buffer of bytes to the bus. + + Return value: number of bytes written or ``None`` on timeout. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + """ + def readline(self) -> Union[str, None]: + """ + Read a line, ending in a newline character. It may return sooner if a timeout + is reached. The timeout is configurable in the constructor. + + Return value: the line read or ``None`` on timeout. + """ + ... + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + tx: PinLike | None = None, + rx: PinLike | None = None, + txbuf: int | None = None, + rxbuf: int | None = None, + timeout: int | None = None, + timeout_char: int | None = None, + invert: int | None = None, + ): + """ + Construct a UART object of the given id. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of two pins. + """ + + @overload + def __init__( + self, + id: ID_T, + /, + baudrate: int = 9600, + bits: int = 8, + parity: int | None = None, + stop: int = 1, + *, + pins: tuple[PinLike, PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct a UART object of the given id from a tuple of four pins. + """ + +class SoftI2C(I2C): + """ + Construct a new software I2C object. The parameters are: + + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + - *timeout* is the maximum time in microseconds to wait for clock + stretching (SCL held low by another device on the bus), after + which an ``OSError(ETIMEDOUT)`` exception is raised. + """ + def readfrom_mem_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_into(self, *args, **kwargs) -> Incomplete: ... + def readfrom_mem(self, *args, **kwargs) -> Incomplete: ... + def writeto_mem(self, *args, **kwargs) -> Incomplete: ... + def scan(self, *args, **kwargs) -> Incomplete: ... + def writeto(self, *args, **kwargs) -> Incomplete: ... + def writevto(self, *args, **kwargs) -> Incomplete: ... + def start(self, *args, **kwargs) -> Incomplete: ... + def readfrom(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def stop(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, scl, sda, *, freq=400000, timeout=50000) -> None: ... + +class SoftSPI(SPI): + """ + Construct a new software SPI object. Additional parameters must be + given, usually at least *sck*, *mosi* and *miso*, and these are used + to initialise the bus. See `SPI.init` for a description of the parameters. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def write_readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def __init__( + self, + baudrate=500000, + *, + polarity=0, + phase=0, + bits=8, + firstbit=MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: ... + +class Timer: + """ + Hardware timers deal with timing of periods and events. Timers are perhaps + the most flexible and heterogeneous kind of hardware in MCUs and SoCs, + differently greatly from a model to a model. MicroPython's Timer class + defines a baseline operation of executing a callback with a given period + (or once after some delay), and allow specific boards to define more + non-standard behaviour (which thus won't be portable to other boards). + + See discussion of :ref:`important constraints ` on + Timer callbacks. + + .. note:: + + Memory can't be allocated inside irq handlers (an interrupt) and so + exceptions raised within a handler don't give much information. See + :func:`micropython.alloc_emergency_exception_buf` for how to get around this + limitation. + + If you are using a WiPy board please refer to :ref:`machine.TimerWiPy ` + instead of this class. + """ + + PERIODIC: Final[int] = 2 + """Timer operating mode.""" + ONE_SHOT: Final[int] = 1 + """Timer operating mode.""" + + @overload + def init( + self, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: ... + @overload + def init( + self, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ) -> None: + """ + Initialise the timer. Example:: + + def mycallback(t): + pass + + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occur upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + """ + ... + def deinit(self) -> None: + """ + Deinitialises the timer. Stops the timer, and disables the timer peripheral. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + period: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + freq: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int = PERIODIC, + tick_hz: int | None = None, + callback: Callable[[Timer], None] | None = None, + ): + """ + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a + virtual timer (if supported by a board). + ``id`` shall not be passed as a keyword argument. + + See ``init`` for parameters of initialisation. + """ + +class WDT: + """ + The WDT 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 machine import WDT + wdt = WDT(timeout=2000) # enable it with a timeout of 2s + wdt.feed() + + Availability of this class: pyboard, WiPy, esp8266, esp32. + """ + def timeout_ms(self, *args, **kwargs) -> Incomplete: ... + def feed(self) -> None: + """ + Feed the WDT to prevent it from resetting the system. The application + should place this call in a sensible place ensuring that the WDT is + only fed after verifying that everything is functioning correctly. + """ + ... + def __init__(self, *, id: int = 0, timeout: int = 5000) -> None: + """ + Create a WDT object and start it. The timeout must be given in milliseconds. + Once it is running the timeout cannot be changed and the WDT cannot be stopped either. + + Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout + cannot be specified, it is determined by the underlying system. + """ + +class Pin: + """ + A pin object is used to control I/O pins (also known as GPIO - general-purpose + input/output). Pin objects are commonly associated with a physical pin that can + drive an output voltage and read input voltages. The pin class has methods to set the mode of + the pin (IN, OUT, etc) and methods to get and set the digital logic level. + For analog control of a pin, see the :class:`ADC` class. + + A pin object is constructed by using an identifier which unambiguously + specifies a certain I/O pin. The allowed forms of the identifier and the + physical pin that the identifier maps to are port-specific. Possibilities + for the identifier are an integer, a string or a tuple with port and pin + number. + + Usage Model:: + + from machine import Pin + + # create an output pin on pin #0 + p0 = Pin(0, Pin.OUT) + + # set the value low then high + p0.value(0) + p0.value(1) + + # create an input pin on pin #2, with a pull up resistor + p2 = Pin(2, Pin.IN, Pin.PULL_UP) + + # read and print the pin value + print(p2.value()) + + # reconfigure pin #0 in input mode with a pull down resistor + p0.init(p0.IN, p0.PULL_DOWN) + + # configure an irq callback + p0.irq(lambda p:print(p)) + """ + + OPEN_DRAIN: Final[int] = 2 + """Selects the pin mode.""" + IRQ_RISING: Final[int] = 1 + """Selects the IRQ trigger type.""" + IRQ_FALLING: Final[int] = 2 + """Selects the IRQ trigger type.""" + IN: Final[int] = 0 + """Selects the pin mode.""" + PULL_UP_22K: Final[int] = 3 + OUT: Final[int] = 1 + """Selects the pin mode.""" + PULL_UP: Final[int] = 2 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_HOLD: Final[int] = 5 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + PULL_DOWN: Final[int] = 0 + """\ + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + """ + DRIVE_2: Final[int] = 3 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_1: Final[int] = 2 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + DRIVE_0: Final[int] = 1 + """\ + Selects the pin drive strength. A port may define additional drive + constants with increasing number corresponding to increasing drive + strength. + """ + PULL_UP_47K: Final[int] = 1 + DRIVE_OFF: Final[int] = 0 + DRIVE_3: Final[int] = 4 + DRIVE_6: Final[int] = 7 + DRIVE_5: Final[int] = 6 + DRIVE_4: Final[int] = 5 + ALT: Incomplete + ALT_OPEN_DRAIN: Incomplete + ANALOG: Incomplete + IRQ_LOW_LEVEL: Incomplete + IRQ_HIGH_LEVEL: Incomplete + def low(self) -> None: + """ + Set pin to "0" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + def irq( + self, + /, + handler: Callable[[Pin], None] | None = None, + trigger: int = (IRQ_FALLING | IRQ_RISING), + *, + priority: int = 1, + wake: int | None = None, + hard: bool = False, + ) -> Callable[..., Incomplete]: + """ + Configure an interrupt handler to be called when the trigger source of the + pin is active. If the pin mode is ``Pin.IN`` then the trigger source is + the external value on the pin. If the pin mode is ``Pin.OUT`` then the + trigger source is the output buffer of the pin. Otherwise, if the pin mode + is ``Pin.OPEN_DRAIN`` then the trigger source is the output buffer for + state '0' and the external pin value for state '1'. + + The arguments are: + + - ``handler`` is an optional function to be called when the interrupt + triggers. The handler must take exactly one argument which is the + ``Pin`` instance. + + - ``trigger`` configures the event which can generate an interrupt. + Possible values are: + + - ``Pin.IRQ_FALLING`` interrupt on falling edge. + - ``Pin.IRQ_RISING`` interrupt on rising edge. + - ``Pin.IRQ_LOW_LEVEL`` interrupt on low level. + - ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level. + + These values can be OR'ed together to trigger on multiple events. + + - ``priority`` sets the priority level of the interrupt. The values it + can take are port-specific, but higher values always represent higher + priorities. + + - ``wake`` selects the power mode in which this interrupt can wake up the + system. It can be ``machine.IDLE``, ``machine.SLEEP`` or ``machine.DEEPSLEEP``. + These values can also be OR'ed together to make a pin generate interrupts in + more than one power mode. + + - ``hard`` if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + Not all ports support this argument. + + This method returns a callback object. + + The following methods are not part of the core Pin API and only implemented on certain ports. + """ + ... + def toggle(self) -> Incomplete: + """ + Toggle output pin from "0" to "1" or vice-versa. + + Availability: cc3200, esp32, esp8266, mimxrt, rp2, samd ports. + """ + ... + def off(self) -> None: + """ + Set pin to "0" output level. + """ + ... + def on(self) -> None: + """ + Set pin to "1" output level. + """ + ... + def init( + self, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Re-initialise the pin using the given parameters. Only those arguments that + are specified will be set. The rest of the pin peripheral state will remain + unchanged. See the constructor documentation for details of the arguments. + + Returns ``None``. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + """ + def high(self) -> None: + """ + Set pin to "1" output level. + + Availability: mimxrt, nrf, renesas-ra, rp2, samd, stm32 ports. + """ + ... + + class cpu: + GPIO_EMC_16: Pin ## = Pin(GPIO_EMC_16) + GPIO_EMC_15: Pin ## = Pin(GPIO_EMC_15) + GPIO_EMC_17: Pin ## = Pin(GPIO_EMC_17) + GPIO_EMC_18: Pin ## = Pin(GPIO_EMC_18) + GPIO_EMC_12: Pin ## = Pin(GPIO_EMC_12) + GPIO_EMC_14: Pin ## = Pin(GPIO_EMC_14) + GPIO_EMC_13: Pin ## = Pin(GPIO_EMC_13) + WAKEUP: Pin ## = Pin(WAKEUP) + GPIO_EMC_24: Pin ## = Pin(GPIO_EMC_24) + GPIO_EMC_23: Pin ## = Pin(GPIO_EMC_23) + GPIO_EMC_25: Pin ## = Pin(GPIO_EMC_25) + GPIO_EMC_19: Pin ## = Pin(GPIO_EMC_19) + GPIO_EMC_20: Pin ## = Pin(GPIO_EMC_20) + GPIO_EMC_22: Pin ## = Pin(GPIO_EMC_22) + GPIO_EMC_21: Pin ## = Pin(GPIO_EMC_21) + GPIO_EMC_01: Pin ## = Pin(GPIO_EMC_01) + GPIO_EMC_00: Pin ## = Pin(GPIO_EMC_00) + GPIO_EMC_02: Pin ## = Pin(GPIO_EMC_02) + GPIO_EMC_03: Pin ## = Pin(GPIO_EMC_03) + GPIO_B1_13: Pin ## = Pin(GPIO_B1_13) + GPIO_B1_15: Pin ## = Pin(GPIO_B1_15) + GPIO_B1_14: Pin ## = Pin(GPIO_B1_14) + GPIO_EMC_11: Pin ## = Pin(GPIO_EMC_11) + GPIO_EMC_09: Pin ## = Pin(GPIO_EMC_09) + GPIO_EMC_08: Pin ## = Pin(GPIO_EMC_08) + GPIO_EMC_10: Pin ## = Pin(GPIO_EMC_10) + GPIO_EMC_04: Pin ## = Pin(GPIO_EMC_04) + GPIO_EMC_05: Pin ## = Pin(GPIO_EMC_05) + GPIO_EMC_07: Pin ## = Pin(GPIO_EMC_07) + GPIO_EMC_06: Pin ## = Pin(GPIO_EMC_06) + GPIO_SD_B1_04: Pin ## = Pin(GPIO_SD_B1_04) + GPIO_SD_B1_03: Pin ## = Pin(GPIO_SD_B1_03) + GPIO_SD_B1_05: Pin ## = Pin(GPIO_SD_B1_05) + GPIO_SD_B1_06: Pin ## = Pin(GPIO_SD_B1_06) + GPIO_SD_B1_00: Pin ## = Pin(GPIO_SD_B1_00) + GPIO_SD_B1_02: Pin ## = Pin(GPIO_SD_B1_02) + GPIO_SD_B1_01: Pin ## = Pin(GPIO_SD_B1_01) + GPIO_EMC_26: Pin ## = Pin(GPIO_EMC_26) + PMIC_ON_REQ: Pin ## = Pin(PMIC_ON_REQ) + GPIO_SD_B1_11: Pin ## = Pin(GPIO_SD_B1_11) + PMIC_STBY_REQ: Pin ## = Pin(PMIC_STBY_REQ) + GPIO_SD_B1_07: Pin ## = Pin(GPIO_SD_B1_07) + GPIO_SD_B1_08: Pin ## = Pin(GPIO_SD_B1_08) + GPIO_SD_B1_10: Pin ## = Pin(GPIO_SD_B1_10) + GPIO_SD_B1_09: Pin ## = Pin(GPIO_SD_B1_09) + GPIO_EMC_31: Pin ## = Pin(GPIO_EMC_31) + GPIO_EMC_30: Pin ## = Pin(GPIO_EMC_30) + GPIO_EMC_32: Pin ## = Pin(GPIO_EMC_32) + GPIO_EMC_33: Pin ## = Pin(GPIO_EMC_33) + GPIO_EMC_27: Pin ## = Pin(GPIO_EMC_27) + GPIO_EMC_29: Pin ## = Pin(GPIO_EMC_29) + GPIO_EMC_28: Pin ## = Pin(GPIO_EMC_28) + GPIO_EMC_41: Pin ## = Pin(GPIO_EMC_41) + GPIO_EMC_39: Pin ## = Pin(GPIO_EMC_39) + GPIO_EMC_38: Pin ## = Pin(GPIO_EMC_38) + GPIO_EMC_40: Pin ## = Pin(GPIO_EMC_40) + GPIO_EMC_34: Pin ## = Pin(GPIO_EMC_34) + GPIO_EMC_35: Pin ## = Pin(GPIO_EMC_35) + GPIO_EMC_37: Pin ## = Pin(GPIO_EMC_37) + GPIO_EMC_36: Pin ## = Pin(GPIO_EMC_36) + GPIO_AD_B1_03: Pin ## = Pin(GPIO_AD_B1_03) + GPIO_AD_B1_02: Pin ## = Pin(GPIO_AD_B1_02) + GPIO_AD_B1_04: Pin ## = Pin(GPIO_AD_B1_04) + GPIO_AD_B1_05: Pin ## = Pin(GPIO_AD_B1_05) + GPIO_AD_B0_15: Pin ## = Pin(GPIO_AD_B0_15) + GPIO_AD_B1_01: Pin ## = Pin(GPIO_AD_B1_01) + GPIO_AD_B1_00: Pin ## = Pin(GPIO_AD_B1_00) + GPIO_B1_11: Pin ## = Pin(GPIO_B1_11) + GPIO_AD_B1_11: Pin ## = Pin(GPIO_AD_B1_11) + GPIO_AD_B1_10: Pin ## = Pin(GPIO_AD_B1_10) + GPIO_AD_B1_12: Pin ## = Pin(GPIO_AD_B1_12) + GPIO_AD_B1_06: Pin ## = Pin(GPIO_AD_B1_06) + GPIO_AD_B1_07: Pin ## = Pin(GPIO_AD_B1_07) + GPIO_AD_B1_09: Pin ## = Pin(GPIO_AD_B1_09) + GPIO_AD_B1_08: Pin ## = Pin(GPIO_AD_B1_08) + GPIO_AD_B0_04: Pin ## = Pin(GPIO_AD_B0_04) + GPIO_AD_B0_03: Pin ## = Pin(GPIO_AD_B0_03) + GPIO_AD_B0_05: Pin ## = Pin(GPIO_AD_B0_05) + GPIO_AD_B0_06: Pin ## = Pin(GPIO_AD_B0_06) + GPIO_AD_B0_00: Pin ## = Pin(GPIO_AD_B0_00) + GPIO_AD_B0_02: Pin ## = Pin(GPIO_AD_B0_02) + GPIO_AD_B0_01: Pin ## = Pin(GPIO_AD_B0_01) + GPIO_AD_B0_14: Pin ## = Pin(GPIO_AD_B0_14) + GPIO_AD_B0_12: Pin ## = Pin(GPIO_AD_B0_12) + GPIO_AD_B0_11: Pin ## = Pin(GPIO_AD_B0_11) + GPIO_AD_B0_13: Pin ## = Pin(GPIO_AD_B0_13) + GPIO_AD_B0_07: Pin ## = Pin(GPIO_AD_B0_07) + GPIO_AD_B0_08: Pin ## = Pin(GPIO_AD_B0_08) + GPIO_AD_B0_10: Pin ## = Pin(GPIO_AD_B0_10) + GPIO_AD_B0_09: Pin ## = Pin(GPIO_AD_B0_09) + GPIO_B1_01: Pin ## = Pin(GPIO_B1_01) + GPIO_B1_00: Pin ## = Pin(GPIO_B1_00) + GPIO_B1_02: Pin ## = Pin(GPIO_B1_02) + GPIO_B1_03: Pin ## = Pin(GPIO_B1_03) + GPIO_B0_13: Pin ## = Pin(GPIO_B0_13) + GPIO_B0_15: Pin ## = Pin(GPIO_B0_15) + GPIO_B0_14: Pin ## = Pin(GPIO_B0_14) + GPIO_AD_B1_13: Pin ## = Pin(GPIO_AD_B1_13) + GPIO_B1_09: Pin ## = Pin(GPIO_B1_09) + GPIO_B1_08: Pin ## = Pin(GPIO_B1_08) + GPIO_B1_10: Pin ## = Pin(GPIO_B1_10) + GPIO_B1_04: Pin ## = Pin(GPIO_B1_04) + GPIO_B1_05: Pin ## = Pin(GPIO_B1_05) + GPIO_B1_07: Pin ## = Pin(GPIO_B1_07) + GPIO_B1_06: Pin ## = Pin(GPIO_B1_06) + GPIO_B0_02: Pin ## = Pin(GPIO_B0_02) + GPIO_B0_01: Pin ## = Pin(GPIO_B0_01) + GPIO_B0_03: Pin ## = Pin(GPIO_B0_03) + GPIO_B0_04: Pin ## = Pin(GPIO_B0_04) + GPIO_AD_B1_14: Pin ## = Pin(GPIO_AD_B1_14) + GPIO_B0_00: Pin ## = Pin(GPIO_B0_00) + GPIO_AD_B1_15: Pin ## = Pin(GPIO_AD_B1_15) + GPIO_B0_12: Pin ## = Pin(GPIO_B0_12) + GPIO_B0_10: Pin ## = Pin(GPIO_B0_10) + GPIO_B0_09: Pin ## = Pin(GPIO_B0_09) + GPIO_B0_11: Pin ## = Pin(GPIO_B0_11) + GPIO_B0_05: Pin ## = Pin(GPIO_B0_05) + GPIO_B0_06: Pin ## = Pin(GPIO_B0_06) + GPIO_B0_08: Pin ## = Pin(GPIO_B0_08) + GPIO_B0_07: Pin ## = Pin(GPIO_B0_07) + def __init__(self, *argv, **kwargs) -> None: ... + + class board: + J5_22: Pin ## = Pin(GPIO_B0_15) + J5_25: Pin ## = Pin(GPIO_B1_02) + J5_24: Pin ## = Pin(GPIO_B1_01) + J5_23: Pin ## = Pin(GPIO_B1_00) + J5_26: Pin ## = Pin(GPIO_B1_03) + J5_30: Pin ## = Pin(GPIO_B0_03) + J5_29: Pin ## = Pin(GPIO_B0_02) + J5_28: Pin ## = Pin(GPIO_B0_01) + J5_06: Pin ## = Pin(GPIO_B0_06) + J5_17: Pin ## = Pin(GPIO_B0_14) + J5_12: Pin ## = Pin(GPIO_B0_09) + J5_08: Pin ## = Pin(GPIO_B0_08) + J5_07: Pin ## = Pin(GPIO_B0_07) + J5_13: Pin ## = Pin(GPIO_B0_10) + J5_16: Pin ## = Pin(GPIO_B0_13) + J5_15: Pin ## = Pin(GPIO_B0_12) + J5_14: Pin ## = Pin(GPIO_B0_11) + LED_GREEN: Pin ## = Pin(GPIO_AD_B0_10) + SCK_RX: Pin ## = Pin(GPIO_AD_B1_11) + MCK: Pin ## = Pin(GPIO_AD_B1_09) + LED_RED: Pin ## = Pin(GPIO_AD_B0_09) + SCK_TX: Pin ## = Pin(GPIO_AD_B1_14) + WS_RX: Pin ## = Pin(GPIO_AD_B1_10) + SD_TX: Pin ## = Pin(GPIO_AD_B1_13) + SD_RX: Pin ## = Pin(GPIO_AD_B1_12) + J5_32: Pin ## = Pin(GPIO_B0_00) + LED_BLUE: Pin ## = Pin(GPIO_AD_B0_11) + J5_36: Pin ## = Pin(GPIO_AD_B1_13) + J5_35: Pin ## = Pin(GPIO_AD_B1_14) + J5_34: Pin ## = Pin(GPIO_AD_B1_15) + J5_37: Pin ## = Pin(GPIO_AD_B1_12) + J5_50: Pin ## = Pin(GPIO_AD_B0_02) + J5_43: Pin ## = Pin(GPIO_AD_B1_01) + J5_42: Pin ## = Pin(GPIO_AD_B1_00) + WS_TX: Pin ## = Pin(GPIO_AD_B1_15) + J3_12: Pin ## = Pin(GPIO_B1_09) + J3_15: Pin ## = Pin(GPIO_AD_B0_15) + J3_14: Pin ## = Pin(GPIO_AD_B0_14) + J3_13: Pin ## = Pin(GPIO_B1_10) + J3_16: Pin ## = Pin(GPIO_AD_B1_00) + J3_20: Pin ## = Pin(GPIO_AD_B0_12) + J3_19: Pin ## = Pin(GPIO_AD_B0_13) + J3_17: Pin ## = Pin(GPIO_AD_B1_01) + J5_05: Pin ## = Pin(GPIO_B0_05) + J3_11: Pin ## = Pin(GPIO_B1_07) + J3_06: Pin ## = Pin(GPIO_EMC_41) + J3_05: Pin ## = Pin(GPIO_B1_06) + J3_04: Pin ## = Pin(GPIO_B1_11) + J3_07: Pin ## = Pin(GPIO_EMC_40) + J3_10: Pin ## = Pin(GPIO_B1_08) + J3_09: Pin ## = Pin(GPIO_B1_04) + J3_08: Pin ## = Pin(GPIO_B1_05) + J4_13: Pin ## = Pin(GPIO_AD_B1_13) + J4_16: Pin ## = Pin(GPIO_AD_B1_02) + J4_15: Pin ## = Pin(GPIO_AD_B1_15) + J4_14: Pin ## = Pin(GPIO_AD_B1_14) + J4_17: Pin ## = Pin(GPIO_AD_B1_03) + J5_04: Pin ## = Pin(GPIO_B0_04) + J4_20: Pin ## = Pin(GPIO_AD_B0_06) + J4_19: Pin ## = Pin(GPIO_AD_B0_07) + J4_04: Pin ## = Pin(GPIO_AD_B1_04) + J4_12: Pin ## = Pin(GPIO_AD_B1_12) + J4_07: Pin ## = Pin(GPIO_AD_B1_07) + J4_06: Pin ## = Pin(GPIO_AD_B1_06) + J4_05: Pin ## = Pin(GPIO_AD_B1_05) + J4_08: Pin ## = Pin(GPIO_AD_B1_08) + J4_11: Pin ## = Pin(GPIO_AD_B1_11) + J4_10: Pin ## = Pin(GPIO_AD_B1_10) + J4_09: Pin ## = Pin(GPIO_AD_B1_09) + def __init__(self, *argv, **kwargs) -> None: ... + + def __init__( + self, + id: Any, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + ) -> None: + """ + Access the pin peripheral (GPIO pin) associated with the given ``id``. If + additional arguments are given in the constructor then they are used to initialise + the pin. Any settings that are not specified will remain in their previous state. + + The arguments are: + + - ``id`` is mandatory and can be an arbitrary object. Among possible value + types are: int (an internal Pin identifier), str (a Pin name), and tuple + (pair of [port, pin]). + + - ``mode`` specifies the pin mode, which can be one of: + + - ``Pin.IN`` - Pin is configured for input. If viewed as an output the pin + is in high-impedance state. + + - ``Pin.OUT`` - Pin is configured for (normal) output. + + - ``Pin.OPEN_DRAIN`` - Pin is configured for open-drain output. Open-drain + output works in the following way: if the output value is set to 0 the pin + is active at a low level; if the output value is 1 the pin is in a high-impedance + state. Not all ports implement this mode, or some might only on certain pins. + + - ``Pin.ALT`` - Pin is configured to perform an alternative function, which is + port specific. For a pin configured in such a way any other Pin methods + (except :meth:`Pin.init`) are not applicable (calling them will lead to undefined, + or a hardware-specific, result). Not all ports implement this mode. + + - ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as + open-drain. Not all ports implement this mode. + + - ``Pin.ANALOG`` - Pin is configured for analog input, see the :class:`ADC` class. + + - ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be + one of: + + - ``None`` - No pull up or down resistor. + - ``Pin.PULL_UP`` - Pull up resistor enabled. + - ``Pin.PULL_DOWN`` - Pull down resistor enabled. + + - ``value`` is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and specifies initial + output pin value if given, otherwise the state of the pin peripheral remains + unchanged. + + - ``drive`` specifies the output power of the pin and can be one of: ``Pin.LOW_POWER``, + ``Pin.MED_POWER`` or ``Pin.HIGH_POWER``. The actual current driving capabilities + are port dependent. Not all ports implement this argument. + + - ``alt`` specifies an alternate function for the pin and the values it can take are + port dependent. This argument is valid only for ``Pin.ALT`` and ``Pin.ALT_OPEN_DRAIN`` + modes. It may be used when a pin supports more than one alternate function. If only + one pin alternate function is supported the this argument is not required. Not all + ports implement this argument. + + As specified above, the Pin class allows to set an alternate function for a particular + pin, but it does not specify any further operations on such a pin. Pins configured in + alternate-function mode are usually not used as GPIO but are instead driven by other + hardware peripherals. The only operation supported on such a pin is re-initialising, + by calling the constructor or :meth:`Pin.init` method. If a pin that is configured in + alternate-function mode is re-initialised with ``Pin.IN``, ``Pin.OUT``, or + ``Pin.OPEN_DRAIN``, the alternate function will be removed from the pin. + """ + + @overload + def __call__(self) -> int: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def __call__(self, x: Any, /) -> None: + """ + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + """ + + @overload + def mode(self) -> int: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self) -> int: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def pull(self, pull: int, /) -> None: + """ + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + + Availability: cc3200, stm32 ports. + """ + + @overload + def drive(self, drive: int, /) -> None: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + ... + + @overload + def drive(self, /) -> int: + """ + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Availability: cc3200 port. + """ + +class Signal(Pin): + """ + The Signal class is a simple extension of the `Pin` class. Unlike Pin, which + can be only in "absolute" 0 and 1 states, a Signal can be in "asserted" + (on) or "deasserted" (off) states, while being inverted (active-low) or + not. In other words, it adds logical inversion support to Pin functionality. + While this may seem a simple addition, it is exactly what is needed to + support wide array of simple digital devices in a way portable across + different boards, which is one of the major MicroPython goals. Regardless + of whether different users have an active-high or active-low LED, a normally + open or normally closed relay - you can develop a single, nicely looking + application which works with each of them, and capture hardware + configuration differences in few lines in the config file of your app. + + Example:: + + from machine import Pin, Signal + + # Suppose you have an active-high LED on pin 0 + led1_pin = Pin(0, Pin.OUT) + # ... and active-low LED on pin 1 + led2_pin = Pin(1, Pin.OUT) + + # Now to light up both of them using Pin class, you'll need to set + # them to different values + led1_pin.value(1) + led2_pin.value(0) + + # Signal class allows to abstract away active-high/active-low + # difference + led1 = Signal(led1_pin, invert=False) + led2 = Signal(led2_pin, invert=True) + + # Now lighting up them looks the same + led1.value(1) + led2.value(1) + + # Even better: + led1.on() + led2.on() + + Following is the guide when Signal vs Pin should be used: + + * Use Signal: If you want to control a simple on/off (including software + PWM!) devices like LEDs, multi-segment indicators, relays, buzzers, or + read simple binary sensors, like normally open or normally closed buttons, + pulled high or low, Reed switches, moisture/flame detectors, etc. etc. + Summing up, if you have a real physical device/sensor requiring GPIO + access, you likely should use a Signal. + + * Use Pin: If you implement a higher-level protocol or bus to communicate + with more complex devices. + + The split between Pin and Signal come from the use cases above and the + architecture of MicroPython: Pin offers the lowest overhead, which may + be important when bit-banging protocols. But Signal adds additional + flexibility on top of Pin, at the cost of minor overhead (much smaller + than if you implemented active-high vs active-low device differences in + Python manually!). Also, Pin is a low-level object which needs to be + implemented for each support board, while Signal is a high-level object + which comes for free once Pin is implemented. + + If in doubt, give the Signal a try! Once again, it is offered to save + developers from the need to handle unexciting differences like active-low + vs active-high signals, and allow other users to share and enjoy your + application, instead of being frustrated by the fact that it doesn't + work for them simply because their LEDs or relays are wired in a slightly + different way. + """ + def off(self) -> None: + """ + Deactivate signal. + """ + ... + def on(self) -> None: + """ + Activate signal. + """ + ... + + @overload + def value(self) -> int: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def value(self, x: Any, /) -> None: + """ + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + """ + + @overload + def __init__(self, pin_obj: PinLike, invert: bool = False, /): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + + @overload + def __init__( + self, + id: PinLike, + /, + mode: int = -1, + pull: int = -1, + *, + value: Any = None, + drive: int | None = None, + alt: int | None = None, + invert: bool = False, + ): + """ + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + """ + +class RTC: + """ + The RTC is an independent clock that keeps track of the date + and time. + + Example usage:: + + rtc = machine.RTC() + rtc.datetime((2020, 1, 21, 2, 10, 32, 36, 0)) + print(rtc.datetime()) + + + + The documentation for RTC is in a poor state;1 + """ + + ALARM0: Final[int] = 0 + """irq trigger source""" + def irq( + self, + /, + *, + trigger: int, + handler: Callable[[RTC], None] | None = None, + wake: int = IDLE, + ) -> None: + """ + Create an irq object triggered by a real time clock alarm. + + - ``trigger`` must be ``RTC.ALARM0`` + - ``handler`` is the function to be called when the callback is triggered. + - ``wake`` specifies the sleep mode from where this interrupt can wake + up the system. + """ + ... + def cancel(self, *args, **kwargs) -> Incomplete: ... + def datetime(self, datetimetuple: Any | None = None) -> Tuple: + """ + Get or set the date and time of the RTC. + + With no arguments, this method returns an 8-tuple with the current + date and time. With 1 argument (being an 8-tuple) it sets the date + and time. + + The 8-tuple has the following format: + + (year, month, day, weekday, hours, minutes, seconds, subseconds) + + The meaning of the ``subseconds`` field is hardware dependent. + """ + ... + + @overload + def init(self) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + + @overload + def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day, hour, minute, second, microsecond, tzinfo)`` + + All eight arguments must be present. The ``microsecond`` and ``tzinfo`` + values are currently ignored but might be used in the future. + + Availability: CC3200, ESP32, MIMXRT, SAMD. The rtc.init() method on + the stm32 and renesas-ra ports just (re-)starts the RTC and does not + accept arguments. + """ + def calibration(self, *args, **kwargs) -> Incomplete: ... + @overload + def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + + @overload + def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int, int], /) -> None: + """ + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + """ + def alarm_cancel(self, alarm_id: int = 0, /) -> None: + """ + Cancel a running alarm. + + The mimxrt port also exposes this function as ``RTC.cancel(alarm_id=0)``, but this is + scheduled to be removed in MicroPython 2.0. + """ + ... + def alarm_left(self, alarm_id: int = 0, /) -> int: + """ + Get the number of milliseconds left before the alarm expires. + """ + ... + @overload + def __init__(self, id: int = 0): + """ + Create an RTC object. See init for parameters of initialization. + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + + @overload + def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]): + """ + Create an RTC object. See init for parameters of initialization. + + The documentation for RTC is in a poor state; better to experiment and use `dir`! + """ + +class SDCard(AbstractBlockDev): + """ + SD cards are one of the most common small form factor removable storage media. + SD cards come in a variety of sizes and physical form factors. MMC cards are + similar removable storage devices while eMMC devices are electrically similar + storage devices designed to be embedded into other systems. All three form + share a common protocol for communication with their host system and high-level + support looks the same for them all. As such in MicroPython they are implemented + in a single class called :class:`machine.SDCard` . + + Both SD and MMC interfaces support being accessed with a variety of bus widths. + When being accessed with a 1-bit wide interface they can be accessed using the + SPI protocol. Different MicroPython hardware platforms support different widths + and pin configurations but for most platforms there is a standard configuration + for any given hardware. In general constructing an ``SDCard`` object with without + passing any parameters will initialise the interface to the default card slot + for the current hardware. The arguments listed below represent the common + arguments that might need to be set in order to use either a non-standard slot + or a non-standard pin assignment. The exact subset of arguments supported will + vary from platform to platform. + + + Implementation-specific details + ------------------------------- + + Different implementations of the ``SDCard`` class on different hardware support + varying subsets of the options above. + + PyBoard + ``````` + + The standard PyBoard has just one slot. No arguments are necessary or supported. + + ESP32 + ````` + + The ESP32 provides two channels of SD/MMC hardware and also supports + access to SD Cards through either of the two SPI ports that are + generally available to the user. As a result the *slot* argument can + take a value between 0 and 3, inclusive. Slots 0 and 1 use the + built-in SD/MMC hardware while slots 2 and 3 use the SPI ports. Slot 0 + supports 1, 4 or 8-bit wide access while slot 1 supports 1 or 4-bit + access; the SPI slots only support 1-bit access. + + .. note:: Slot 0 is used to communicate with on-board flash memory + on most ESP32 modules and so will be unavailable to the + user. + + .. note:: Most ESP32 modules that provide an SD card slot using the + dedicated hardware only wire up 1 data pin, so the default + value for *width* is 1. + + The pins used by the dedicated SD/MMC hardware are fixed. The pins + used by the SPI hardware can be reassigned. + + .. note:: If any of the SPI signals are remapped then all of the SPI + signals will pass through a GPIO multiplexer unit which + can limit the performance of high frequency signals. Since + the normal operating speed for SD cards is 40MHz this can + cause problems on some cards. + + The default (and preferred) pin assignment are as follows: + + ====== ====== ====== ====== ====== + Slot 0 1 2 3 + ------ ------ ------ ------ ------ + Signal Pin Pin Pin Pin + ====== ====== ====== ====== ====== + sck 6 14 18 14 + cmd 11 15 + cs 5 15 + miso 19 12 + mosi 23 13 + D0 7 2 + D1 8 4 + D2 9 12 + D3 10 13 + D4 16 + D5 17 + D6 5 + D7 18 + ====== ====== ====== ====== ====== + + cc3200 + `````` + + You can set the pins used for SPI access by passing a tuple as the + *pins* argument. + + *Note:* The current cc3200 SD card implementation names the this class + :class:`machine.SD` rather than :class:`machine.SDCard` . + """ + def present(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + """ + + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + def deinit(self, *args, **kwargs) -> Incomplete: ... + def init(self, *args, **kwargs) -> Incomplete: ... + def info(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... + +class SPI: + """ + SPI is a synchronous serial protocol that is driven by a controller. At the + physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices + can share the same bus. Each device should have a separate, 4th signal, + CS (Chip Select), to select a particular device on a bus with which + communication takes place. Management of a CS signal should happen in + user code (via machine.Pin class). + + Both hardware and software SPI implementations exist via the + :ref:`machine.SPI ` and `machine.SoftSPI` classes. Hardware SPI uses underlying + hardware support of the system to perform the reads/writes and is usually + efficient and fast but may have restrictions on which pins can be used. + Software SPI is implemented by bit-banging and can be used on any pin but + is not as efficient. These classes have the same methods available and + differ primarily in the way they are constructed. + + Example usage:: + + from machine import SPI, Pin + + spi = SPI(0, baudrate=400000) # Create SPI peripheral 0 at frequency of 400kHz. + # Depending on the use case, extra parameters may be required + # to select the bus characteristics and/or pins to use. + cs = Pin(4, mode=Pin.OUT, value=1) # Create chip-select on pin 4. + + try: + cs(0) # Select peripheral. + spi.write(b"12345678") # Write 8 bytes, and don't care about received data. + finally: + cs(1) # Deselect peripheral. + + try: + cs(0) # Select peripheral. + rxdata = spi.read(8, 0x42) # Read 8 bytes while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + rxdata = bytearray(8) + try: + cs(0) # Select peripheral. + spi.readinto(rxdata, 0x42) # Read 8 bytes inplace while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + txdata = b"12345678" + rxdata = bytearray(len(txdata)) + try: + cs(0) # Select peripheral. + spi.write_readinto(txdata, rxdata) # Simultaneously write and read bytes. + finally: + cs(1) # Deselect peripheral. + """ + + LSB: Final[int] = 1 + """set the first bit to be the least significant bit""" + MSB: Final[int] = 0 + """set the first bit to be the most significant bit""" + CONTROLLER: Incomplete + def deinit(self) -> None: + """ + Turn off the SPI bus. + """ + ... + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + + @overload + def init( + self, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ) -> None: + """ + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependent on the platform hardware. The actual + rate may be determined by printing the SPI object. + """ + def write_readinto(self, write_buf: AnyReadableBuf, read_buf: AnyWritableBuf, /) -> int: + """ + Write the bytes from ``write_buf`` while reading into ``read_buf``. The + buffers can be the same or different, but both buffers must have the + same length. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def read(self, nbytes: int, write: int = 0x00, /) -> bytes: + """ + Read a number of bytes specified by ``nbytes`` while continuously writing + the single byte given by ``write``. + Returns a ``bytes`` object with the data that was read. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the bytes contained in ``buf``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + """ + ... + def readinto(self, buf: AnyWritableBuf, write: int = 0x00, /) -> int: + """ + Read into the buffer specified by ``buf`` while continuously writing the + single byte given by ``write``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes read. + """ + ... + @overload + def __init__(self, id: int, /): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + sck: PinLike | None = None, + mosi: PinLike | None = None, + miso: PinLike | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + + @overload + def __init__( + self, + id: int, + /, + baudrate: int = 1_000_000, + *, + polarity: int = 0, + phase: int = 0, + bits: int = 8, + firstbit: int = MSB, + pins: tuple[PinLike, PinLike, PinLike] | None = None, + ): + """ + Construct an SPI object on the given bus, *id*. Values of *id* depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + """ + +class ADCBlock: + @overload + def connect(self, channel: int, **kwargs) -> ADC: ... + @overload + def connect(self, source: PinLike, **kwargs) -> ADC: ... + @overload + def connect(self, channel: int, source: PinLike, **kwargs) -> ADC: + """ + Connect up a channel on the ADC peripheral so it is ready for sampling, + and return an :ref:`ADC ` object that represents that connection. + + The *channel* argument must be an integer, and *source* must be an object + (for example a :ref:`Pin `) which can be connected up for sampling. + + If only *channel* is given then it is configured for sampling. + + If only *source* is given then that object is connected to a default + channel ready for sampling. + + If both *channel* and *source* are given then they are connected together + and made ready for sampling. + + Any additional keyword arguments are used to configure the returned ADC object, + via its :meth:`init ` method. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/math.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/math.pyi new file mode 100644 index 000000000..dcc5cea90 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/math.pyi @@ -0,0 +1,269 @@ +""" +Mathematical functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/math.html + +CPython module: :mod:`python:math` https://docs.python.org/3/library/math.html . + +The ``math`` module provides some basic mathematical functions for +working with floating-point numbers. + +*Note:* On the pyboard, floating-point numbers have 32-bit precision. + +Availability: not available on WiPy. Floating point support required +for this module. + +--- +Module: 'math' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import SupportsFloat, Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +inf: float = inf +nan: float = nan +pi: float = 3.141592653589793 +"""the ratio of a circle's circumference to its diameter""" +e: float = 2.718281828459045 +"""base of the natural logarithm""" +tau: float = 6.283185307179586 + +def ldexp(x: SupportsFloat, exp: int, /) -> float: + """ + Return ``x * (2**exp)``. + """ + ... + +def lgamma(x: SupportsFloat, /) -> float: + """ + Return the natural logarithm of the gamma function of ``x``. + """ + ... + +def trunc(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards 0. + """ + ... + +def isclose(*args, **kwargs) -> Incomplete: ... +def gamma(x: SupportsFloat, /) -> float: + """ + Return the gamma function of ``x``. + """ + ... + +def isnan(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is not-a-number + """ + ... + +def isfinite(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is finite. + """ + ... + +def isinf(x: SupportsFloat, /) -> bool: + """ + Return ``True`` if ``x`` is infinite. + """ + ... + +def sqrt(x: SupportsFloat, /) -> float: + """ + Return the square root of ``x``. + """ + ... + +def sinh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic sine of ``x``. + """ + ... + +def log(x: SupportsFloat, /) -> float: + """ + With one argument, return the natural logarithm of *x*. + + With two arguments, return the logarithm of *x* to the given *base*. + """ + ... + +def tan(x: SupportsFloat, /) -> float: + """ + Return the tangent of ``x``. + """ + ... + +def tanh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic tangent of ``x``. + """ + ... + +def log2(x: SupportsFloat, /) -> float: + """ + Return the base-2 logarithm of ``x``. + """ + ... + +def log10(x: SupportsFloat, /) -> float: + """ + Return the base-10 logarithm of ``x``. + """ + ... + +def sin(x: SupportsFloat, /) -> float: + """ + Return the sine of ``x``. + """ + ... + +def modf(x: SupportsFloat, /) -> Tuple: + """ + Return a tuple of two floats, being the fractional and integral parts of + ``x``. Both return values have the same sign as ``x``. + """ + ... + +def radians(x: SupportsFloat, /) -> float: + """ + Return degrees ``x`` converted to radians. + """ + ... + +def atanh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic tangent of ``x``. + """ + ... + +def atan2(y: SupportsFloat, x: SupportsFloat, /) -> float: + """ + Return the principal value of the inverse tangent of ``y/x``. + """ + ... + +def atan(x: SupportsFloat, /) -> float: + """ + Return the inverse tangent of ``x``. + """ + ... + +def ceil(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards positive infinity. + """ + ... + +def copysign(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return ``x`` with the sign of ``y``. + """ + ... + +def frexp(x: SupportsFloat, /) -> tuple[float, 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 acos(x: SupportsFloat, /) -> float: + """ + Return the inverse cosine of ``x``. + """ + ... + +def pow(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Returns ``x`` to the power of ``y``. + """ + ... + +def asinh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic sine of ``x``. + """ + ... + +def acosh(x: SupportsFloat, /) -> float: + """ + Return the inverse hyperbolic cosine of ``x``. + """ + ... + +def asin(x: SupportsFloat, /) -> float: + """ + Return the inverse sine of ``x``. + """ + ... + +def factorial(*args, **kwargs) -> Incomplete: ... +def fabs(x: SupportsFloat, /) -> float: + """ + Return the absolute value of ``x``. + """ + ... + +def expm1(x: SupportsFloat, /) -> float: + """ + Return ``exp(x) - 1``. + """ + ... + +def floor(x: SupportsFloat, /) -> int: + """ + Return an integer, being ``x`` rounded towards negative infinity. + """ + ... + +def fmod(x: SupportsFloat, y: SupportsFloat, /) -> float: + """ + Return the remainder of ``x/y``. + """ + ... + +def cos(x: SupportsFloat, /) -> float: + """ + Return the cosine of ``x``. + """ + ... + +def degrees(x: SupportsFloat, /) -> float: + """ + Return radians ``x`` converted to degrees. + """ + ... + +def cosh(x: SupportsFloat, /) -> float: + """ + Return the hyperbolic cosine of ``x``. + """ + ... + +def exp(x: SupportsFloat, /) -> float: + """ + Return the exponential of ``x``. + """ + ... + +def erf(x: SupportsFloat, /) -> float: + """ + Return the error function of ``x``. + """ + ... + +def erfc(x: SupportsFloat, /) -> float: + """ + Return the complementary error function of ``x``. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/micropython.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/micropython.pyi new file mode 100644 index 000000000..42982aee2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/micropython.pyi @@ -0,0 +1,346 @@ +""" +Access and control MicroPython internals. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/micropython.html + +--- +Module: 'micropython' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import mp_available +from typing import Any, Callable, Optional, Tuple, overload +from typing_extensions import Awaitable, ParamSpec, TypeAlias, TypeVar + +_T = TypeVar("_T") +_F = TypeVar("_F", bound=Callable[..., Any]) +Const_T = TypeVar("Const_T", int, float, str, bytes, Tuple) +_Param = ParamSpec("_Param") +_Ret = TypeVar("_Ret") + +@overload +def opt_level() -> int: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def opt_level(level: int, /) -> None: + """ + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + """ + +@overload +def mem_info() -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +@overload +def mem_info(verbose: Any, /) -> None: + """ + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + """ + +def kbd_intr(chr: int) -> None: + """ + Set the character that will raise a `KeyboardInterrupt` exception. By + default this is set to 3 during script execution, corresponding to Ctrl-C. + Passing -1 to this function will disable capture of Ctrl-C, and passing 3 + will restore it. + + This function can be used to prevent the capturing of Ctrl-C on the + incoming stream of characters that is usually used for the REPL, in case + that stream is used for other purposes. + """ + ... + +@overload +def qstr_info() -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +@overload +def qstr_info(verbose: bool, /) -> None: + """ + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + """ + +def schedule(func: Callable[[_T], None], arg: _T, /) -> None: + """ + Schedule the function *func* to be executed "very soon". The function + is passed the value *arg* as its single argument. "Very soon" means that + the MicroPython runtime will do its best to execute the function at the + earliest possible time, given that it is also trying to be efficient, and + that the following conditions hold: + + - A scheduled function will never preempt another scheduled function. + - Scheduled functions are always executed "between opcodes" which means + that all fundamental Python operations (such as appending to a list) + are guaranteed to be atomic. + - A given port may define "critical regions" within which scheduled + functions will never be executed. Functions may be scheduled within + a critical region but they will not be executed until that region + is exited. An example of a critical region is a preempting interrupt + handler (an IRQ). + + A use for this function is to schedule a callback from a preempting IRQ. + Such an IRQ puts restrictions on the code that runs in the IRQ (for example + the heap may be locked) and scheduling a function to call later will lift + those restrictions. + + On multi-threaded ports, the scheduled function's behaviour depends on + whether the Global Interpreter Lock (GIL) is enabled for the specific port: + + - If GIL is enabled, the function can preempt any thread and run in its + context. + - If GIL is disabled, the function will only preempt the main thread and run + in its context. + + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite queue to hold the scheduled functions and `schedule()` + will raise a `RuntimeError` if the queue is full. + """ + ... + +def stack_use() -> int: + """ + Return an integer representing the current amount of stack that is being + used. The absolute value of this is not particularly useful, rather it + should be used to compute differences in stack usage at different points. + """ + ... + +def heap_unlock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def const(expr: Const_T, /) -> Const_T: + """ + Used to declare that the expression is a constant so that the compiler can + optimise it. The use of this function should be as follows:: + + from micropython import const + + CONST_X = const(123) + CONST_Y = const(2 * CONST_X + 1) + + Constants declared this way are still accessible as global variables from + outside the module they are declared in. On the other hand, if a constant + begins with an underscore then it is hidden, it is not available as a global + variable, and does not take up any memory during execution. + + This `const` function is recognised directly by the MicroPython parser and is + provided as part of the :mod:`micropython` module mainly so that scripts can be + written which run under both CPython and MicroPython, by following the above + pattern. + """ + ... + +def heap_lock() -> int: + """ + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + """ + ... + +def alloc_emergency_exception_buf(size: int, /) -> None: + """ + Allocate *size* bytes of RAM for the emergency exception buffer (a good + size is around 100 bytes). The buffer is used to create exceptions in cases + when normal RAM allocation would fail (eg within an interrupt handler) and + therefore give useful traceback information in these situations. + + A good way to use this function is to put it at the start of your main script + (eg ``boot.py`` or ``main.py``) and then the emergency exception buffer will be active + for all the code following it. + """ + ... + +class RingIO: + def readinto(self, buf, nbytes: Optional[Any] = None) -> int: + """ + Read available bytes into the provided ``buf``. If ``nbytes`` is + specified then read at most that many bytes. Otherwise, read at + most ``len(buf)`` bytes. + + Return value: Integer count of the number of bytes read into ``buf``. + """ + ... + def write(self, buf) -> int: + """ + Non-blocking write of bytes from ``buf`` into the ringbuffer, limited + by the available space in the ringbuffer. + + Return value: Integer count of bytes written. + """ + ... + def readline(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read a line, ending in a newline character or return if one exists in + the buffer, else return available bytes in buffer. If ``nbytes`` is + specified then read at most that many bytes. + + Return value: a bytes object containing the line read. + """ + ... + def any(self) -> int: + """ + Returns an integer counting the number of characters that can be read. + """ + ... + def read(self, nbytes: Optional[Any] = None) -> bytes: + """ + Read available characters. This is a non-blocking function. If ``nbytes`` + is specified then read at most that many bytes, otherwise read as much + data as possible. + + Return value: a bytes object containing the bytes read. Will be + zero-length bytes object if no data is available. + """ + ... + def close(self) -> Incomplete: + """ + No-op provided as part of standard `stream` interface. Has no effect + on data in the ringbuffer. + """ + ... + def __init__(self, size) -> None: ... + +# decorators +@mp_available() # force merge +def viper(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + The Viper code emitter is not fully compliant. It supports special Viper native data types in pursuit of performance. + Integer processing is non-compliant because it uses machine words: arithmetic on 32 bit hardware is performed modulo 2**32. + Like the Native emitter Viper produces machine instructions but further optimisations are performed, substantially increasing + performance especially for integer arithmetic and bit manipulations. + See: https://docs.micropython.org/en/latest/reference/speed_python.html?highlight=viper#the-native-code-emitter + """ + ... + +@mp_available() # force merge +def native(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This causes the MicroPython compiler to emit native CPU opcodes rather than bytecode. + It covers the bulk of the MicroPython functionality, so most functions will require no adaptation. + See: https://docs.micropython.org/en/latest/reference/speed_python.html#the-native-code-emitter + """ + ... + +@mp_available(macro="MICROPY_EMIT_INLINE_THUMB") # force merge +def asm_thumb(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code. + The assembler code is written is a subset of the ARM Thumb-2 instruction set, and is executed on the target CPU. + + Availability: Only on specific boards where MICROPY_EMIT_INLINE_THUMB is defined. + See: https://docs.micropython.org/en/latest/reference/asm_thumb2_index.html + """ + ... + +@mp_available(port="esp8266") # force merge +def asm_xtensa(_func: Callable[_Param, _Ret], /) -> Callable[_Param, _Ret]: + """ + This decorator is used to mark a function as containing inline assembler code for the esp8266. + The assembler code is written in the Xtensa instruction set, and is executed on the target CPU. + + Availability: Only on eps8266 boards. + """ + ... + # See : + # - https://github.com/orgs/micropython/discussions/12965 + # - https://github.com/micropython/micropython/pull/16731 diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/mimxrt.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/mimxrt.pyi new file mode 100644 index 000000000..8ecccefdf --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/mimxrt.pyi @@ -0,0 +1,14 @@ +""" +Module: 'mimxrt' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class Flash: + def readblocks(self, *args, **kwargs) -> Incomplete: ... + def writeblocks(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/mip/__init__.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/mip/__init__.pyi new file mode 100644 index 000000000..773af6948 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/mip/__init__.pyi @@ -0,0 +1,15 @@ +from _typeshed import Incomplete +from micropython import const as const + +_PACKAGE_INDEX: str +_CHUNK_SIZE: int +allowed_mip_url_prefixes: Incomplete + +def _ensure_path_exists(path) -> None: ... +def _chunk(src, dest) -> None: ... +def _check_exists(path, short_hash): ... +def _rewrite_url(url, branch=None): ... +def _download_file(url, dest): ... +def _install_json(package_json_url, index, target, version, mpy): ... +def _install_package(package, index, target, version, mpy): ... +def install(package, index=None, target=None, version=None, mpy: bool = True) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/network.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/network.pyi new file mode 100644 index 000000000..96bf53a10 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/network.pyi @@ -0,0 +1,554 @@ +""" +Network configuration. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/network.html + +This module provides network drivers and routing configuration. To use this +module, a MicroPython variant/build with network capabilities must be installed. +Network drivers for specific hardware are available within this module and are +used to configure hardware network interface(s). Network services provided +by configured interfaces are then available for use via the :mod:`socket` +module. + +For example:: + + # connect/ show IP config a specific network interface + # see below for examples of specific drivers + import network + import time + nic = network.Driver(...) + if not nic.isconnected(): + nic.connect() + print("Waiting for connection...") + while not nic.isconnected(): + time.sleep(1) + print(nic.ipconfig("addr4")) + + # now use socket as usual + import socket + addr = socket.getaddrinfo('micropython.org', 80)[0][-1] + s = socket.socket() + s.connect(addr) + s.send(b'GET / HTTP/1.1 + +Host: micropython.org + + + +') + data = s.recv(1000) + s.close() + +--- +Module: 'network' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Protocol, Callable, List, Optional, Any, Tuple, overload, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar +from machine import Pin, SPI +from abc import abstractmethod + +STA_IF: Final[int] = 0 +AP_IF: Final[int] = 1 + +def route(*args, **kwargs) -> Incomplete: ... +def hostname(name: Optional[Any] = None) -> Incomplete: + """ + Get or set the hostname that will identify this device on the network. It will + be used by all interfaces. + + This hostname is used for: + * Sending to the DHCP server in the client request. (If using DHCP) + * Broadcasting via mDNS. (If enabled) + + If the *name* parameter is provided, the hostname will be set to this value. + If the function is called without parameters, it returns the current + hostname. + + A change in hostname is typically only applied during connection. For DHCP + this is because the hostname is part of the DHCP client request, and the + implementation of mDNS in most ports only initialises the hostname once + during connection. For this reason, you must set the hostname before + activating/connecting your network interfaces. + + The length of the hostname is limited to 32 characters. + :term:`MicroPython ports ` may choose to set a lower + limit for memory reasons. If the given name does not fit, a `ValueError` + is raised. + + The default hostname is typically the name of the board. + """ + ... + +def ipconfig(param: Optional[str] = None, *args, **kwargs) -> str: + """ + Get or set global IP-configuration parameters. + Supported parameters are the following (availability of a particular + parameter depends on the port and the specific network interface): + + * ``dns`` Get/set DNS server. This method can support both, IPv4 and + IPv6 addresses. + * ``prefer`` (``4/6``) Specify which address type to return, if a domain + name has both A and AAAA records. Note, that this does not clear the + local DNS cache, so that any previously obtained addresses might not + change. + """ + ... + +def country(code: Optional[Any] = None) -> Incomplete: + """ + Get or set the two-letter ISO 3166-1 Alpha-2 country code to be used for + radio compliance. + + If the *code* parameter is provided, the country will be set to this value. + If the function is called without parameters, it returns the current + country. + + The default code ``"XX"`` represents the "worldwide" region. + """ + ... + +class PPP: + """ + Create a PPP driver object. + + Arguments are: + + - *stream* is any object that supports the stream protocol, but is most commonly a + :class:`machine.UART` instance. This stream object must have an ``irq()`` method + and an ``IRQ_RXIDLE`` constant, for use by `PPP.connect`. + """ + + SEC_NONE: Final[int] = 0 + """The type of connection security.""" + SEC_PAP: Final[int] = 1 + """The type of connection security.""" + SEC_CHAP: Final[int] = 2 + """The type of connection security.""" + def status(self) -> Incomplete: + """ + Returns the PPP status. + """ + ... + def ipconfig(self, param) -> Incomplete: + """ + See `AbstractNIC.ipconfig`. + """ + ... + def isconnected(self) -> bool: + """ + Returns ``True`` if the PPP link is connected and up. + Returns ``False`` otherwise. + """ + ... + def poll(self) -> Incomplete: + """ + Poll the underlying stream for data, and pass it up the PPP stack. + This is called automatically if the stream is a UART with a RXIDLE interrupt, + so it's not usually necessary to call it manually. + """ + ... + def ifconfig(self, configtuple: Any | None = None) -> Incomplete: + """ + See `AbstractNIC.ifconfig`. + """ + ... + def config(self, config_parameters) -> Incomplete: + """ + Sets or gets parameters of the PPP interface. The only parameter that can be + retrieved and set is the underlying stream, using:: + + stream = PPP.config("stream") + PPP.config(stream=stream) + """ + ... + def connect(self, security=SEC_NONE, user=None, key=None) -> Incomplete: + """ + Initiate a PPP connection with the given parameters: + + - *security* is the type of security, either ``PPP.SEC_NONE``, ``PPP.SEC_PAP``, + or ``PPP.SEC_CHAP``. + - *user* is an optional user name to use with the security mode. + - *key* is an optional password to use with the security mode. + + When this method is called the underlying stream has its interrupt configured to call + `PPP.poll` via ``stream.irq(ppp.poll, stream.IRQ_RXIDLE)``. This makes sure the + stream is polled, and data passed up the PPP stack, wheverver data becomes available + on the stream. + + The connection proceeds asynchronously, in the background. + """ + ... + def disconnect(self) -> Incomplete: + """ + Terminate the connection. This must be called to cleanly close the PPP connection. + """ + ... + def __init__(self, stream) -> None: ... + +class LAN: + """ + Create a LAN driver object, initialise the LAN module using the given + PHY driver name, and return the LAN object. + + Arguments are: + + - *id* is the number of the Ethernet port, either 0 or 1. + - *phy_type* is the name of the PHY driver. For most board the on-board PHY has to be used and + is the default. Suitable values are port specific. + - *phy_addr* specifies the address of the PHY interface. As with *phy_type*, the hardwired value has + to be used for most boards and that value is the default. + - *ref_clk_mode* specifies, whether the data clock is provided by the Ethernet controller or + the PYH interface. + The default value is the one that matches the board. If set to ``LAN.OUT`` or ``Pin.OUT`` + or ``True``, the clock is driven by the Ethernet controller, if set to ``LAN.IN`` + or ``Pin.IN`` or ``False``, the clock is driven by the PHY interface. + + For example, with the Seeed Arch Mix board you can use:: + + nic = LAN(0, phy_type=LAN.PHY_LAN8720, phy_addr=1, ref_clk_mode=Pin.IN) + """ + + PHY_KSZ8081: Final[int] = 0 + PHY_DP83848: Final[int] = 2 + PHY_LAN8720: Final[int] = 3 + PHY_RTL8211F: Final[int] = 4 + IN: Final[int] = 0 + PHY_DP83825: Final[int] = 1 + OUT: Final[int] = 1 + def ipconfig(self, *args, **kwargs) -> Incomplete: ... + def status(self) -> Incomplete: + """ + Returns the LAN status. + """ + ... + def isconnected(self) -> bool: + """ + Returns ``True`` if the physical Ethernet link is connected and up. + Returns ``False`` otherwise. + """ + ... + @overload + def active(self, /) -> bool: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ + + @overload + def active(self, is_active: bool | int, /) -> None: + """ + With a parameter, it sets the interface active if *state* is true, otherwise it + sets it inactive. + Without a parameter, it returns the state. + """ + def ifconfig(self, configtuple: Any | None = None) -> Tuple: + """ + Get/set IP address, subnet mask, gateway and DNS. + + When called with no arguments, this method returns a 4-tuple with the above information. + + To set the above values, pass a 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + ... + def config(self, config_parameters) -> Incomplete: + """ + Sets or gets parameters of the LAN interface. The only parameter that can be + retrieved is the MAC address, using:: + + mac = LAN.config("mac") + + The parameters that can be set are: + + - ``trace=n`` sets trace levels; suitable values are: + + - 2: trace TX + - 4: trace RX + - 8: full trace + + - ``low_power=bool`` sets or clears low power mode, valid values being ``False`` + or ``True``. + """ + ... + def __init__(self, id, *, phy_type=0, phy_addr=0, ref_clk_mode=0) -> None: ... + +class WLANWiPy: + @overload + def __init__(self, id: int = 0, /): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def __init__( + self, + id: int, + /, + *, + mode: int, + ssid: str, + auth: tuple[str, str], + channel: int, + antenna: int, + ): + """ + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + + .. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + """ + + @overload + def mode(self) -> int: + """ + Get or set the WLAN mode. + """ + + @overload + def mode(self, mode: int, /) -> None: + """ + Get or set the WLAN mode. + """ + + @overload + def ssid(self) -> str: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def ssid(self, ssid: str, /) -> None: + """ + Get or set the SSID when in AP mode. + """ + + @overload + def auth(self) -> int: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def auth(self, auth: int, /) -> None: + """ + Get or set the authentication type when in AP mode. + """ + + @overload + def channel(self) -> int: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def channel(self, channel: int, /) -> None: + """ + Get or set the channel (only applicable in AP mode). + """ + + @overload + def antenna(self) -> int: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def antenna(self, antenna: int, /) -> None: + """ + Get or set the antenna type (external or internal). + """ + + @overload + def mac(self) -> bytes: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + + @overload + def mac(self, mac: bytes, /) -> None: + """ + Get or set a 6-byte long bytes object with the MAC address. + """ + +class AbstractNIC: + @overload + @abstractmethod + def active(self, /) -> bool: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def active(self, is_active: bool | int, /) -> None: + """ + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behaviour of calling them on inactive interface is + undefined). + """ + + @overload + @abstractmethod + def connect(self, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def connect(self, service_id: Any, key: str | None = None, /, **kwargs: Any) -> None: + """ + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifier types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + """ + + @overload + @abstractmethod + def status(self) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def status(self, param: str, /) -> Any: + """ + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + """ + + @overload + @abstractmethod + def ifconfig(self) -> tuple[str, str, str, str]: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def ifconfig(self, ip_mask_gateway_dns: tuple[str, str, str, str], /) -> None: + """ + ``Note:`` This function is deprecated, use `ipconfig()` instead. + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + """ + + @overload + @abstractmethod + def config(self, param: str, /) -> Any: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ + + @overload + @abstractmethod + def config(self, **kwargs: Any) -> None: + """ + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ipconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as SSID) and WiFi channel + ap.config(ssid='My AP', channel=11) + # Query params one by one + print(ap.config('ssid')) + print(ap.config('channel')) + """ diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ntptime.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ntptime.pyi new file mode 100644 index 000000000..3b374f65d --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ntptime.pyi @@ -0,0 +1,5 @@ +host: str +timeout: int + +def time(): ... +def settime() -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/onewire.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/onewire.pyi new file mode 100644 index 000000000..2a07804f2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/onewire.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class OneWireError(Exception): ... + +class OneWire: + SEARCH_ROM: int + MATCH_ROM: int + SKIP_ROM: int + pin: Incomplete + def __init__(self, pin) -> None: ... + def reset(self, required: bool = False): ... + def readbit(self): ... + def readbyte(self): ... + def readinto(self, buf) -> None: ... + def writebit(self, value): ... + def writebyte(self, value): ... + def write(self, buf) -> None: ... + def select_rom(self, rom) -> None: ... + def scan(self): ... + def _search_rom(self, l_rom, diff): ... + def crc8(self, data): ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/platform.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/platform.pyi new file mode 100644 index 000000000..a84342847 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/platform.pyi @@ -0,0 +1,51 @@ +""" +Access to underlying platform’s identifying data. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/platform.html + +CPython module: :mod:`python:platform` https://docs.python.org/3/library/platform.html . + +This module tries to retrieve as much platform-identifying data as possible. It +makes this information available via function APIs. + +--- +Module: 'platform' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def platform() -> str: + """ + Returns a string identifying the underlying platform. This string is composed + of several substrings in the following order, delimited by dashes (``-``): + + - the name of the platform system (e.g. Unix, Windows or MicroPython) + - the MicroPython version + - the architecture of the platform + - the version of the underlying platform + - the concatenation of the name of the libc that MicroPython is linked to + and its corresponding version. + + For example, this could be + ``"MicroPython-1.20.0-xtensa-IDFv4.2.4-with-newlib3.0.0"``. + """ + ... + +def python_compiler() -> str: + """ + Returns a string identifying the compiler used for compiling MicroPython. + """ + ... + +def libc_ver() -> Tuple: + """ + Returns a tuple of strings *(lib, version)*, where *lib* is the name of the + libc that MicroPython is linked to, and *version* the corresponding version + of this libc. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/pyproject.toml b/publish/micropython-v1_26_1-mimxrt-stubs/pyproject.toml new file mode 100644 index 000000000..37edecc93 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/pyproject.toml @@ -0,0 +1,111 @@ +[project] +name = "micropython-mimxrt-stubs" +description = "MicroPython stubs" +version = "1.26.1.post1" +readme = "README.md" +license = "MIT" +authors = [ + { name = "Jos Verlinde", email = "josverl@users.noreply.github.com" }, +] +classifiers = [ + "Typing :: Stubs Only", + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Implementation :: MicroPython", + "Operating System :: OS Independent", + "Topic :: Text Editors :: Integrated Development Environments (IDE)", + "Topic :: Software Development :: Documentation", + "Topic :: Software Development :: Embedded Systems", + "Topic :: Software Development :: Testing", + "Natural Language :: English", +] +dependencies = [ + "micropython-stdlib-stubs ~=1.26.0", +] + +[project.urls] +homepage = "https://github.com/josverl/micropython-stubs#micropython-stubs" +documentation = "https://micropython-stubs.readthedocs.io/" +repository = "https://github.com/josverl/micropython-stubs" + +[tool.poetry] +exclude = [ + "*.ps1", + "*.py", + "**/__pycache__", + "**/dist", +] +include = [ + "**/*.py", + "**/*.pyi", +] +packages = [ + { include = "__builtins__.pyi" }, + { include = "_boot.pyi" }, + { include = "_onewire.pyi" }, + { include = "binascii.pyi" }, + { include = "cmath.pyi" }, + { include = "cryptolib.pyi" }, + { include = "deflate.pyi" }, + { include = "dht.pyi" }, + { include = "ds18x20.pyi" }, + { include = "errno.pyi" }, + { include = "framebuf.pyi" }, + { include = "gc.pyi" }, + { include = "hashlib.pyi" }, + { include = "heapq.pyi" }, + { include = "lwip.pyi" }, + { include = "machine.pyi" }, + { include = "math.pyi" }, + { include = "micropython.pyi" }, + { include = "mimxrt.pyi" }, + { include = "mip/__init__.pyi" }, + { include = "network.pyi" }, + { include = "ntptime.pyi" }, + { include = "onewire.pyi" }, + { include = "platform.pyi" }, + { include = "random.pyi" }, + { include = "requests/__init__.pyi" }, + { include = "select.pyi" }, + { include = "socket.pyi" }, + { include = "time.pyi" }, + { include = "tls.pyi" }, + { include = "uarray.pyi" }, + { include = "uasyncio.pyi" }, + { include = "ubinascii.pyi" }, + { include = "ubluetooth.pyi" }, + { include = "ucollections.pyi" }, + { include = "ucryptolib.pyi" }, + { include = "uctypes.pyi" }, + { include = "uerrno.pyi" }, + { include = "uhashlib.pyi" }, + { include = "uheapq.pyi" }, + { include = "uio.pyi" }, + { include = "ujson.pyi" }, + { include = "umachine.pyi" }, + { include = "uos.pyi" }, + { include = "uplatform.pyi" }, + { include = "urandom.pyi" }, + { include = "ure.pyi" }, + { include = "urequests.pyi" }, + { include = "uselect.pyi" }, + { include = "usocket.pyi" }, + { include = "ussl.pyi" }, + { include = "ustruct.pyi" }, + { include = "usys.pyi" }, + { include = "utime.pyi" }, + { include = "uwebsocket.pyi" }, + { include = "uzlib.pyi" }, + { include = "vfs.pyi" }, + { include = "webrepl.pyi" }, + { include = "webrepl_setup.pyi" }, + { include = "websocket.pyi" }, +] + +[build-system] +requires = [ + "poetry-core>=1.0.0", +] +build-backend = "poetry.core.masonry.api" diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/random.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/random.pyi new file mode 100644 index 000000000..52c922661 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/random.pyi @@ -0,0 +1,115 @@ +""" +Random numbers. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/random.html + +This module implements a pseudo-random number generator (PRNG). + +CPython module: :mod:`python:random` https://docs.python.org/3/library/random.html . . + +.. note:: + + The following notation is used for intervals: + + - () are open interval brackets and do not include their endpoints. + For example, (0, 1) means greater than 0 and less than 1. + In set notation: (0, 1) = {x | 0 < x < 1}. + + - [] are closed interval brackets which include all their limit points. + For example, [0, 1] means greater than or equal to 0 and less than + or equal to 1. + In set notation: [0, 1] = {x | 0 <= x <= 1}. + +.. note:: + + The :func:`randrange`, :func:`randint` and :func:`choice` functions are only + available if the ``MICROPY_PY_RANDOM_EXTRA_FUNCS`` configuration option is + enabled. + +--- +Module: 'random' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import Subscriptable +from typing import overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_T = TypeVar("_T") + +@overload +def randrange(stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +@overload +def randrange(start: int, stop: int, step: int, /) -> int: + """ + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + """ + +def random() -> int: + """ + Return a random floating point number in the range [0.0, 1.0). + """ + ... + +def seed(n: int | None = None, /) -> None: + """ + Initialise the random number generator module with the seed *n* which should + be an integer. When no argument (or ``None``) is passed in it will (if + supported by the port) initialise the PRNG with a true random number + (usually a hardware generated random number). + + The ``None`` case only works if ``MICROPY_PY_RANDOM_SEED_INIT_FUNC`` is + enabled by the port, otherwise it raises ``ValueError``. + """ + ... + +def uniform(a: float, b: float) -> int: + """ + Return a random floating point number N such that *a* <= N <= *b* for *a* <= *b*, + and *b* <= N <= *a* for *b* < *a*. + """ + ... + +def choice(sequence: Subscriptable, /) -> None: + """ + Chooses and returns one item at random from *sequence* (tuple, list or + any object that supports the subscript operation). + """ + ... + +def randint(a: int, b: int, /) -> int: + """ + Return a random integer in the range [*a*, *b*]. + """ + ... + +def getrandbits(n: int, /) -> int: + """ + Return an integer with *n* random bits (0 <= n <= 32). + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/requests/__init__.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/requests/__init__.pyi new file mode 100644 index 000000000..74386f89b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/requests/__init__.pyi @@ -0,0 +1,21 @@ +from _typeshed import Incomplete + +class Response: + raw: Incomplete + encoding: str + _cached: Incomplete + def __init__(self, f) -> None: ... + def close(self) -> None: ... + @property + def content(self): ... + @property + def text(self): ... + def json(self): ... + +def request(method, url, data=None, json=None, headers=None, stream=None, auth=None, timeout=None, parse_headers: bool = True): ... +def head(url, **kw): ... +def get(url, **kw): ... +def post(url, **kw): ... +def put(url, **kw): ... +def patch(url, **kw): ... +def delete(url, **kw): ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/select.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/select.pyi new file mode 100644 index 000000000..c1893e88b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/select.pyi @@ -0,0 +1,118 @@ +""" +Wait for events on a set of streams. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/select.html + +CPython module: :mod:`python:select` https://docs.python.org/3/library/select.html . + +This module provides functions to efficiently wait for events on multiple +`streams ` (select streams which are ready for operations). + +--- +Module: 'select' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Any, Iterable, Iterator, List, Optional, Tuple, Final +from _typeshed import Incomplete +from typing_extensions import Awaitable, TypeAlias, TypeVar + +POLLOUT: Final[int] = 4 +POLLIN: Final[int] = 1 +POLLHUP: Final[int] = 16 +POLLERR: Final[int] = 8 + +def select( + rlist: Iterable[Any], + wlist: Iterable[Any], + xlist: Iterable[Any], + timeout: int = -1, + /, +) -> None: + """ + Wait for activity on a set of objects. + + This function is provided by some MicroPython ports for compatibility + and is not efficient. Usage of :class:`Poll` is recommended instead. + """ + ... + +class poll: + """ + Create an instance of the Poll class. + """ + def __init__(self) -> None: ... + def register(self, obj, eventmask: Optional[Any] = None) -> None: + """ + Register `stream` *obj* for polling. *eventmask* is logical OR of: + + * ``select.POLLIN`` - data available for reading + * ``select.POLLOUT`` - more data can be written + + Note that flags like ``select.POLLHUP`` and ``select.POLLERR`` are + *not* valid as input eventmask (these are unsolicited events which + will be returned from `poll()` regardless of whether they are asked + for). This semantics is per POSIX. + + *eventmask* defaults to ``select.POLLIN | select.POLLOUT``. + + It is OK to call this function multiple times for the same *obj*. + Successive calls will update *obj*'s eventmask to the value of + *eventmask* (i.e. will behave as `modify()`). + """ + ... + def unregister(self, obj) -> Incomplete: + """ + Unregister *obj* from polling. + """ + ... + def modify(self, obj, eventmask) -> None: + """ + Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError` + is raised with error of ENOENT. + """ + ... + def poll(self, timeout=-1, /) -> List: + """ + Wait for at least one of the registered objects to become ready or have an + exceptional condition, with optional timeout in milliseconds (if *timeout* + arg is not specified or -1, there is no timeout). + + Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in + tuple, depending on a platform and version, so don't assume that its size is 2. + The ``event`` element specifies which events happened with a stream and + is a combination of ``select.POLL*`` constants described above. Note that + flags ``select.POLLHUP`` and ``select.POLLERR`` can be returned at any time + (even if were not asked for), and must be acted on accordingly (the + corresponding stream unregistered from poll and likely closed), because + otherwise all further invocations of `poll()` may return immediately with + these flags set for this stream again. + + In case of timeout, an empty list is returned. + + Admonition:Difference to CPython + :class: attention + + Tuples returned may contain more than 2 elements as described above. + """ + ... + def ipoll(self, timeout=-1, flags=0, /) -> Iterator[Tuple]: + """ + Like :meth:`poll.poll`, but instead returns an iterator which yields a + `callee-owned tuple`. This function provides an efficient, allocation-free + way to poll on streams. + + If *flags* is 1, one-shot behaviour for events is employed: streams for + which events happened will have their event masks automatically reset + (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream + won't be processed until new mask is set with `poll.modify()`. This + behaviour is useful for asynchronous I/O schedulers. + + Admonition:Difference to CPython + :class: attention + + This function is a MicroPython extension. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/socket.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/socket.pyi new file mode 100644 index 000000000..9acb73654 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/socket.pyi @@ -0,0 +1,426 @@ +""" +Socket module. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/socket.html + +CPython module: :mod:`python:socket` https://docs.python.org/3/library/socket.html . + +This module provides access to the BSD socket interface. + +Admonition:Difference to CPython + :class: attention + + For efficiency and consistency, socket objects in MicroPython implement a `stream` + (file-like) interface directly. In CPython, you need to convert a socket to + a file-like object using `makefile()` method. This method is still supported + by MicroPython (but is a no-op), so where compatibility with CPython matters, + be sure to use it. + +Socket address format(s) +------------------------ + +The native socket address format of the ``socket`` module is an opaque data type +returned by `getaddrinfo` function, which must be used to resolve textual address +(including numeric addresses):: + + sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1] + # You must use getaddrinfo() even for numeric addresses + sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1] + # Now you can use that address + sock.connect(sockaddr) + +Using `getaddrinfo` is the most efficient (both in terms of memory and processing +power) and portable way to work with addresses. + +However, ``socket`` module (note the difference with native MicroPython +``socket`` module described here) provides CPython-compatible way to specify +addresses using tuples, as described below. Note that depending on a +:term:`MicroPython port`, ``socket`` module can be builtin or need to be +installed from `micropython-lib` (as in the case of :term:`MicroPython Unix port`), +and some ports still accept only numeric addresses in the tuple format, +and require to use `getaddrinfo` function to resolve domain names. + +Summing up: + +* Always use `getaddrinfo` when writing portable applications. +* Tuple addresses described below can be used as a shortcut for + quick hacks and interactive use, if your port supports them. + +Tuple address format for ``socket`` module: + +* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with + dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and + integer port number in the range 1-65535. Note the domain names are not + accepted as *ipv4_address*, they should be resolved first using + `socket.getaddrinfo()`. +* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address* + is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``, + and *port* is an integer port number in the range 1-65535. *flowinfo* + must be 0. *scopeid* is the interface scope identifier for link-local + addresses. Note the domain names are not accepted as *ipv6_address*, + they should be resolved first using `socket.getaddrinfo()`. Availability + of IPv6 support depends on a :term:`MicroPython port`. + +--- +Module: 'socket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Literal, Tuple, overload, Final +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf +from typing_extensions import Awaitable, TypeAlias, TypeVar + +SOCK_RAW: Final[int] = 3 +SOCK_STREAM: Final[int] = 1 +"""Socket types.""" +SOCK_DGRAM: Final[int] = 2 +"""Socket types.""" +MSG_PEEK: Final[int] = 1 +SO_REUSEADDR: Final[int] = 4 +SOL_SOCKET: Final[int] = 1 +SO_BROADCAST: Final[int] = 32 +TCP_NODELAY: Final[int] = 64 +AF_INET6: Final[int] = 10 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +IPPROTO_IP: Final[int] = 0 +AF_INET: Final[int] = 2 +"""Address family types. Availability depends on a particular :term:`MicroPython port`.""" +MSG_DONTWAIT: Final[int] = 2 +IP_DROP_MEMBERSHIP: Final[int] = 1025 +IPPROTO_TCP: Final[int] = 6 +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IP_ADD_MEMBERSHIP: Final[int] = 1024 +IPPROTO_UDP: Incomplete +"""\ +IP protocol numbers. Availability depends on a particular :term:`MicroPython port`. +Note that you don't need to specify these in a call to `socket.socket()`, +because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and +`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants +is as an argument to `setsockopt()`. +""" +IPPROTO_SEC: Incomplete +"""Special protocol value to create SSL-compatible socket.""" +_Address: TypeAlias = tuple[str, int] | tuple[str, int, int, int] | str +Socket: TypeAlias = socket + +def reset(*args, **kwargs) -> Incomplete: ... +def print_pcbs(*args, **kwargs) -> Incomplete: ... +def getaddrinfo( + host: str, + port: int, + af: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, + /, +) -> list[tuple[int, int, int, str, tuple[str, int] | tuple[str, int, int, int]]]: + """ + Translate the host/port argument into a sequence of 5-tuples that contain all the + necessary arguments for creating a socket connected to that service. Arguments + *af*, *type*, and *proto* (which have the same meaning as for the `socket()` function) + can be used to filter which kind of addresses are returned. If a parameter is not + specified or zero, all combinations of addresses can be returned (requiring + filtering on the user side). + + The resulting list of 5-tuples has the following structure:: + + (family, type, proto, canonname, sockaddr) + + The following example shows how to connect to a given url:: + + s = socket.socket() + # This assumes that if "type" is not specified, an address for + # SOCK_STREAM will be returned, which may be not true + s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1]) + + Recommended use of filtering params:: + + s = socket.socket() + # Guaranteed to return an address which can be connect'ed to for + # stream operation. + s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1]) + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.gaierror`` exception (`OSError` subclass) in case + of error in this function. MicroPython doesn't have ``socket.gaierror`` + and raises OSError directly. Note that error numbers of `getaddrinfo()` + form a separate namespace and may not match error numbers from + the :mod:`errno` module. To distinguish `getaddrinfo()` errors, they are + represented by negative numbers, whereas standard system errors are + positive numbers (error numbers are accessible using ``e.args[0]`` property + from an exception object). The use of negative values is a provisional + detail which may change in the future. + """ + ... + +def callback(*args, **kwargs) -> Incomplete: ... + +class socket: + """ + A unix like socket, for more information see module ``socket``'s description. + + The name, `Socket`, used for typing is not the same as the runtime name, `socket` (note lowercase `s`). + The reason for this difference is that the runtime uses `socket` as both a class name and as a method name and + this is not possible within code written entirely in Python and therefore not possible within typing code. + """ + def recvfrom(self, bufsize: int, /) -> Tuple: + """ + Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a + bytes object representing the data received and *address* is the address of the socket sending + the data. + + See the `recv` function for an explanation of the optional *flags* argument. + """ + ... + def recv(self, bufsize: int, /) -> bytes: + """ + Receive data from the socket. The return value is a bytes object representing the data + received. The maximum amount of data to be received at once is specified by bufsize. + + Most ports support the optional *flags* argument. Available *flags* are defined as constants + in the socket module and have the same meaning as in CPython. ``MSG_PEEK`` and ``MSG_DONTWAIT`` + are supported on all ports which accept the *flags* argument. + """ + ... + + @overload + def makefile(self, mode: Literal["rb", "wb", "rwb"] = "rb", buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + + @overload + def makefile(self, mode: str, buffering: int = 0, /) -> Socket: + """ + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + Admonition:Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + Admonition:Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + """ + def listen(self, backlog: int = ..., /) -> None: + """ + Enable a server to accept connections. If *backlog* is specified, it must be at least 0 + (if it's lower, it will be set to 0); and specifies the number of unaccepted connections + that the system will allow before refusing new connections. If not specified, a default + reasonable value is chosen. + """ + ... + def settimeout(self, value: float | None, /) -> None: + """ + **Note**: Not every port supports this method, see below. + + Set a timeout on blocking socket operations. The value argument can be a nonnegative floating + point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations + will raise an `OSError` exception if the timeout period value has elapsed before the operation has + completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket + is put in blocking mode. + + Not every :term:`MicroPython port` supports this method. A more portable and + generic solution is to use `select.poll` object. This allows to wait on + multiple objects at the same time (and not just on sockets, but on generic + `stream` objects which support polling). Example:: + + # Instead of: + s.settimeout(1.0) # time in seconds + s.read(10) # may timeout + + # Use: + poller = select.poll() + poller.register(s, select.POLLIN) + res = poller.poll(1000) # time in milliseconds + if not res: + # s is still not ready for input, i.e. operation timed out + + Admonition:Difference to CPython + :class: attention + + CPython raises a ``socket.timeout`` exception in case of timeout, + which is an `OSError` subclass. MicroPython raises an OSError directly + instead. If you use ``except OSError:`` to catch the exception, + your code will work both in MicroPython and CPython. + """ + ... + def sendall(self, bytes: AnyReadableBuf, /) -> int: + """ + Send all data to the socket. The socket must be connected to a remote socket. + Unlike `send()`, this method will try to send all of data, by sending data + chunk by chunk consecutively. + + The behaviour of this method on non-blocking sockets is undefined. Due to this, + on MicroPython, it's recommended to use `write()` method instead, which + has the same "no short writes" policy for blocking sockets, and will return + number of bytes sent on non-blocking sockets. + """ + ... + def setsockopt(self, level: int, optname: int, value: AnyReadableBuf | int, /) -> None: + """ + Set the value of the given socket option. The needed symbolic constants are defined in the + socket module (SO_* etc.). The *value* can be an integer or a bytes-like object representing + a buffer. + """ + ... + def setblocking(self, value: bool, /) -> None: + """ + Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking, + else to blocking mode. + + This method is a shorthand for certain `settimeout()` calls: + + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)`` + """ + ... + def sendto(self, bytes: AnyReadableBuf, address: _Address, /) -> None: + """ + Send data to the socket. The socket should not be connected to a remote socket, since the + destination socket is specified by *address*. + """ + ... + def readline(self) -> bytes: + """ + Read a line, ending in a newline character. + + Return value: the line read. + """ + ... + + @overload + def readinto(self, buf: AnyWritableBuf, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None: + """ + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + """ + + @overload + def read(self) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + + @overload + def read(self, size: int, /) -> bytes: + """ + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + """ + def close(self) -> None: + """ + Mark the socket closed and release all resources. Once that happens, all future operations + on the socket object will fail. The remote end will receive EOF indication if + supported by protocol. + + Sockets are automatically closed when they are garbage-collected, but it is recommended + to `close()` them explicitly as soon you finished working with them. + """ + ... + def connect(self, address: _Address | bytes, /) -> None: + """ + Connect to a remote socket at *address*. + """ + ... + def send(self, bytes: AnyReadableBuf, /) -> int: + """ + Send data to the socket. The socket must be connected to a remote socket. + Returns number of bytes sent, which may be smaller than the length of data + ("short write"). + """ + ... + def bind(self, address: _Address | bytes, /) -> None: + """ + Bind the socket to *address*. The socket must not already be bound. + """ + ... + def accept(self) -> Tuple: + """ + Accept a connection. The socket must be bound to an address and listening for connections. + The return value is a pair (conn, address) where conn is a new socket object usable to send + and receive data on the connection, and address is the address bound to the socket on the + other end of the connection. + """ + ... + def write(self, buf: AnyReadableBuf, /) -> int: + """ + Write the buffer of bytes to the socket. This function will try to + write all data to a socket (no "short writes"). This may be not possible + with a non-blocking socket though, and returned value will be less than + the length of *buf*. + + Return value: number of bytes written. + """ + ... + def __init__( + self, + af: int = AF_INET, + type: int = SOCK_STREAM, + proto: int = IPPROTO_TCP, + /, + ) -> None: + """ + Create a new socket using the given address family, socket type and + protocol number. Note that specifying *proto* in most cases is not + required (and not recommended, as some MicroPython ports may omit + ``IPPROTO_*`` constants). Instead, *type* argument will select needed + protocol automatically:: + + # Create STREAM TCP socket + socket(AF_INET, SOCK_STREAM) + # Create DGRAM UDP socket + socket(AF_INET, SOCK_DGRAM) + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/time.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/time.pyi new file mode 100644 index 000000000..1f091db69 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/time.pyi @@ -0,0 +1,306 @@ +""" +Time related functions. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/time.html + +CPython module: :mod:`python:time` https://docs.python.org/3/library/time.html . + +The ``time`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports +use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. +The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC. +Epoch year may be determined with ``gmtime(0)[0]``. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. + +--- +Module: 'time' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _TimeTuple +from typing import Tuple +from typing_extensions import Awaitable, TypeAlias, TypeVar + +_TicksMs: TypeAlias = int +_TicksUs: TypeAlias = int +_TicksCPU: TypeAlias = int +_Ticks = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int) + +def ticks_diff(ticks1: _Ticks, ticks2: _Ticks, /) -> int: + """ + Measure ticks difference between values returned from `ticks_ms()`, `ticks_us()`, + or `ticks_cpu()` functions, as a signed value which may wrap around. + + The argument order is the same as for subtraction + operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. + However, values returned by `ticks_ms()`, etc. functions may wrap around, so + directly using subtraction on them will produce incorrect result. That is why + `ticks_diff()` is needed, it implements modular (or more specifically, ring) + arithmetic to produce correct result even for wrap-around values (as long as they not + too distant in between, see below). The function returns **signed** value in the range + [*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for + two's-complement signed binary integers). If the result is negative, it means that + *ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that + *ticks1* occurred after *ticks2*. This holds **only** if *ticks1* and *ticks2* + are apart from each other for no more than *TICKS_PERIOD/2-1* ticks. If that does + not hold, incorrect result will be returned. Specifically, if two tick values are + apart for *TICKS_PERIOD/2-1* ticks, that value will be returned by the function. + However, if *TICKS_PERIOD/2* of real-time ticks has passed between them, the + function will return *-TICKS_PERIOD/2* instead, i.e. result value will wrap around + to the negative range of possible values. + + Informal rationale of the constraints above: Suppose you are locked in a room with no + means to monitor passing of time except a standard 12-notch clock. Then if you look at + dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a + long sleep), then once you finally look again, it may seem to you that only 1 hour + has passed. To avoid this mistake, just look at the clock regularly. Your application + should do the same. "Too long sleep" metaphor also maps directly to application + behaviour: don't let your application run any single task for too long. Run tasks + in steps, and do time-keeping in between. + + `ticks_diff()` is designed to accommodate various usage patterns, among them: + + * Polling with timeout. In this case, the order of events is known, and you will deal + only with positive results of `ticks_diff()`:: + + # Wait for GPIO pin to be asserted, but at most 500us + start = time.ticks_us() + while pin.value() == 0: + if time.ticks_diff(time.ticks_us(), start) > 500: + raise TimeoutError + + * Scheduling events. In this case, `ticks_diff()` result may be negative + if an event is overdue:: + + # This code snippet is not optimized + now = time.ticks_ms() + scheduled_time = task.scheduled_time() + if ticks_diff(scheduled_time, now) > 0: + print("Too early, let's nap") + sleep_ms(ticks_diff(scheduled_time, now)) + task.run() + elif ticks_diff(scheduled_time, now) == 0: + print("Right at time!") + task.run() + elif ticks_diff(scheduled_time, now) < 0: + print("Oops, running late, tell task to run faster!") + task.run(run_faster=true) + + Note: Do not pass `time()` values to `ticks_diff()`, you should use + normal mathematical operations on them. But note that `time()` may (and will) + also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem . + """ + ... + +def ticks_add(ticks: _Ticks, delta: int, /) -> _Ticks: + """ + Offset ticks value by a given number, which can be either positive or negative. + Given a *ticks* value, this function allows to calculate ticks value *delta* + ticks before or after it, following modular-arithmetic definition of tick values + (see `ticks_ms()` above). *ticks* parameter must be a direct result of call + to `ticks_ms()`, `ticks_us()`, or `ticks_cpu()` functions (or from previous + call to `ticks_add()`). However, *delta* can be an arbitrary integer number + or numeric expression. `ticks_add()` is useful for calculating deadlines for + events/tasks. (Note: you must use `ticks_diff()` function to work with + deadlines.) + + Examples:: + + # Find out what ticks value there was 100ms ago + print(ticks_add(time.ticks_ms(), -100)) + + # Calculate deadline for operation and test for it + deadline = ticks_add(time.ticks_ms(), 200) + while ticks_diff(deadline, time.ticks_ms()) > 0: + do_a_little_of_something() + + # Find out TICKS_MAX used by this port + print(ticks_add(0, -1)) + """ + ... + +def ticks_cpu() -> _TicksCPU: + """ + Similar to `ticks_ms()` and `ticks_us()`, but with the highest possible resolution + in the system. This is usually CPU clocks, and that's why the function is named that + way. But it doesn't have to be a CPU clock, some other timing source available in a + system (e.g. high-resolution timer) can be used instead. The exact timing unit + (resolution) of this function is not specified on ``time`` module level, but + documentation for a specific port may provide more specific information. This + function is intended for very fine benchmarking or very tight real-time loops. + Avoid using it in portable code. + + Availability: Not every port implements this function. + """ + ... + +def time() -> int: + """ + Returns the number of seconds, as an integer, since the Epoch, assuming that + underlying RTC is set and maintained as described above. If an RTC is not set, this + function returns number of seconds since a port-specific reference point in time (for + embedded boards without a battery-backed RTC, usually since power up or reset). If you + want to develop portable MicroPython application, you should not rely on this function + to provide higher than second precision. If you need higher precision, absolute + timestamps, use `time_ns()`. If relative times are acceptable then use the + `ticks_ms()` and `ticks_us()` functions. If you need calendar time, `gmtime()` or + `localtime()` without an argument is a better choice. + + Admonition:Difference to CPython + :class: attention + + In CPython, this function returns number of + seconds since Unix epoch, 1970-01-01 00:00 UTC, as a floating-point, + usually having microsecond precision. With MicroPython, only Unix port + uses the same Epoch, and if floating-point precision allows, + returns sub-second precision. Embedded hardware usually doesn't have + floating-point precision to represent both long time ranges and subsecond + precision, so they use integer value with second precision. Some embedded + hardware also lacks battery-powered RTC, so returns number of seconds + since last power-up or from other relative, hardware-specific point + (e.g. reset). + """ + ... + +def ticks_ms() -> int: + """ + Returns an increasing millisecond counter with an arbitrary reference point, that + wraps around after some value. + + The wrap-around value is not explicitly exposed, but we will + refer to it as *TICKS_MAX* to simplify discussion. Period of the values is + *TICKS_PERIOD = TICKS_MAX + 1*. *TICKS_PERIOD* is guaranteed to be a power of + two, but otherwise may differ from port to port. The same period value is used + for all of `ticks_ms()`, `ticks_us()`, `ticks_cpu()` functions (for + simplicity). Thus, these functions will return a value in range [*0* .. + *TICKS_MAX*], inclusive, total *TICKS_PERIOD* values. Note that only + non-negative values are used. For the most part, you should treat values returned + by these functions as opaque. The only operations available for them are + `ticks_diff()` and `ticks_add()` functions described below. + + Note: Performing standard mathematical operations (+, -) or relational + operators (<, <=, >, >=) directly on these value will lead to invalid + result. Performing mathematical operations and then passing their results + as arguments to `ticks_diff()` or `ticks_add()` will also lead to + invalid results from the latter functions. + """ + ... + +def ticks_us() -> _TicksUs: + """ + Just like `ticks_ms()` above, but in microseconds. + """ + ... + +def time_ns() -> int: + """ + Similar to `time()` but returns nanoseconds since the Epoch, as an integer (usually + a big integer, so will allocate on the heap). + """ + ... + +def localtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_us(us: int, /) -> None: + """ + Delay for given number of microseconds, should be positive or 0. + + This function attempts to provide an accurate delay of at least *us* + microseconds, but it may take longer if the system has other higher priority + processing to perform. + """ + ... + +def gmtime(secs: int | None = None, /) -> Tuple: + """ + Convert the time *secs* expressed in seconds since the Epoch (see above) into an + 8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)`` + If *secs* is not provided or None, then the current time from the RTC is used. + + The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a + date-time tuple in local time. + + The format of the entries in the 8-tuple are: + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + """ + ... + +def sleep_ms(ms: int, /) -> None: + """ + Delay for given number of milliseconds, should be positive or 0. + + This function will delay for at least the given number of milliseconds, but + may take longer than that if other processing must take place, for example + interrupt handlers or other threads. Passing in 0 for *ms* will still allow + this other processing to occur. Use `sleep_us()` for more precise delays. + """ + ... + +def mktime(local_time: _TimeTuple, /) -> int: + """ + This is inverse function of localtime. It's argument is a full 8-tuple + which expresses a time as per localtime. It returns an integer which is + the number of seconds since the time epoch. + """ + ... + +def sleep(seconds: float, /) -> None: + """ + Sleep for the given number of seconds. Some boards may accept *seconds* as a + floating-point number to sleep for a fractional number of seconds. Note that + other boards may not accept a floating-point argument, for compatibility with + them use `sleep_ms()` and `sleep_us()` functions. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/tls.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/tls.pyi new file mode 100644 index 000000000..34f93f51e --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/tls.pyi @@ -0,0 +1,26 @@ +""" +Module: 'tls' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Final +from _typeshed import Incomplete + +PROTOCOL_TLS_SERVER: Final[int] = 1 +PROTOCOL_DTLS_CLIENT: Final[int] = 2 +PROTOCOL_DTLS_SERVER: Final[int] = 3 +PROTOCOL_TLS_CLIENT: Final[int] = 0 +MBEDTLS_VERSION: Final[str] = "Mbed TLS 3.6.2" +CERT_NONE: Final[int] = 0 +CERT_OPTIONAL: Final[int] = 1 +CERT_REQUIRED: Final[int] = 2 + +class SSLContext: + def load_verify_locations(self, *args, **kwargs) -> Incomplete: ... + def set_ciphers(self, *args, **kwargs) -> Incomplete: ... + def wrap_socket(self, *args, **kwargs) -> Incomplete: ... + def load_cert_chain(self, *args, **kwargs) -> Incomplete: ... + def get_ciphers(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uarray.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uarray.pyi new file mode 100644 index 000000000..e5c0fe438 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uarray.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to array +from array import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uasyncio.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uasyncio.pyi new file mode 100644 index 000000000..3d69c52f2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uasyncio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to asyncio +from asyncio import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ubinascii.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ubinascii.pyi new file mode 100644 index 000000000..3a77380ad --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ubinascii.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to binascii +from binascii import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ubluetooth.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ubluetooth.pyi new file mode 100644 index 000000000..4046c2c75 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ubluetooth.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to bluetooth +from bluetooth import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ucollections.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ucollections.pyi new file mode 100644 index 000000000..5b2ffea32 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ucollections.pyi @@ -0,0 +1,15 @@ +""" +Collection and container types. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/collections.html + +CPython module: :mod:`python:collections` https://docs.python.org/3/library/collections.html . + +This module implements advanced collection and container types to +hold/accumulate various objects. + +--- +Module: 'ucollections' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" +# import module from stdlib/module +from collections import * \ No newline at end of file diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ucryptolib.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ucryptolib.pyi new file mode 100644 index 000000000..6b8b56a68 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ucryptolib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to cryptolib +from cryptolib import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uctypes.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uctypes.pyi new file mode 100644 index 000000000..a74802960 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uctypes.pyi @@ -0,0 +1,164 @@ +""" +Access binary data in a structured way. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/uctypes.html + +This module implements "foreign data interface" for MicroPython. The idea +behind it is similar to CPython's ``ctypes`` modules, but the actual API is +different, streamlined and optimized for small size. The basic idea of the +module is to define data structure layout with about the same power as the +C language allows, and then access it using familiar dot-syntax to reference +sub-fields. + +--- +Module: 'uctypes' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from typing import Dict, Tuple, Any, Final, Generator +from _typeshed import Incomplete +from _mpy_shed import AnyReadableBuf, AnyWritableBuf, mp_available +from typing_extensions import Awaitable, TypeAlias, TypeVar + +VOID: Final[int] = 0 +"""\ +``VOID`` is an alias for ``UINT8``, and is provided to conveniently define +C's void pointers: ``(uctypes.PTR, uctypes.VOID)``. +""" +NATIVE: Final[int] = 2 +"""\ +Layout type for a native structure - with data endianness and alignment +conforming to the ABI of the system on which MicroPython runs. +""" +PTR: Final[int] = 536870912 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +SHORT: Final[int] = 402653184 +LONGLONG: Final[int] = 939524096 +INT8: Final[int] = 134217728 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +LITTLE_ENDIAN: Final[int] = 0 +"""\ +Layout type for a little-endian packed structure. (Packed means that every +field occupies exactly as many bytes as defined in the descriptor, i.e. +the alignment is 1). +""" +LONG: Final[int] = 671088640 +UINT: Final[int] = 536870912 +ULONG: Final[int] = 536870912 +ULONGLONG: Final[int] = 805306368 +USHORT: Final[int] = 268435456 +UINT8: Final[int] = 0 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT16: Final[int] = 268435456 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT32: Final[int] = 536870912 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +UINT64: Final[int] = 805306368 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT64: Final[int] = 939524096 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +BFUINT16: Final[int] = -805306368 +BFUINT32: Final[int] = -536870912 +BFUINT8: Final[int] = -1073741824 +BFINT8: Final[int] = -939524096 +ARRAY: Final[int] = -1073741824 +"""\ +Type constants for pointers and arrays. Note that there is no explicit +constant for structures, it's implicit: an aggregate type without ``PTR`` +or ``ARRAY`` flags is a structure. +""" +BFINT16: Final[int] = -671088640 +BFINT32: Final[int] = -402653184 +BF_LEN: Final[int] = 22 +INT: Final[int] = 671088640 +INT16: Final[int] = 402653184 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +INT32: Final[int] = 671088640 +"""\ +Integer types for structure descriptors. Constants for 8, 16, 32, +and 64 bit types are provided, both signed and unsigned. +""" +FLOAT64: Final[int] = -134217728 +"""Floating-point types for structure descriptors.""" +BF_POS: Final[int] = 17 +BIG_ENDIAN: Final[int] = 1 +"""Layout type for a big-endian packed structure.""" +FLOAT32: Final[int] = -268435456 +"""Floating-point types for structure descriptors.""" +_property: TypeAlias = Incomplete +_descriptor: TypeAlias = Tuple | Dict + +def sizeof(struct: struct | _descriptor | dict, layout_type: int = NATIVE, /) -> int: + """ + Return size of data structure in bytes. The *struct* argument can be + either a structure class or a specific instantiated structure object + (or its aggregate field). + """ + ... + +def bytes_at(addr: int, size: int, /) -> bytes: + """ + Capture memory at the given address and size as bytes object. As bytes + object is immutable, memory is actually duplicated and copied into + bytes object, so if memory contents change later, created object + retains original value. + """ + ... + +def bytearray_at(addr: int, size: int, /) -> bytearray: + """ + Capture memory at the given address and size as bytearray object. + Unlike bytes_at() function above, memory is captured by reference, + so it can be both written too, and you will access current value + at the given memory address. + """ + ... + +def addressof(obj: AnyReadableBuf, /) -> int: + """ + Return address of an object. Argument should be bytes, bytearray or + other object supporting buffer protocol (and address of this buffer + is what actually returned). + """ + ... + +class struct: + """ + Module contents + --------------- + """ + def __init__(self, addr: int | struct, descriptor: _descriptor, layout_type: int = NATIVE, /) -> None: + """ + Instantiate a "foreign data structure" object based on structure address in + memory, descriptor (encoded as a dictionary), and layout type (see below). + """ + ... + @mp_available() # force push + def __getattr__(self, a): ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uerrno.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uerrno.pyi new file mode 100644 index 000000000..8d34ba6b7 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uerrno.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to errno +from errno import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uhashlib.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uhashlib.pyi new file mode 100644 index 000000000..8b4b7bc77 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uhashlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to hashlib +from hashlib import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uheapq.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uheapq.pyi new file mode 100644 index 000000000..71c066fcf --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uheapq.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to heapq +from heapq import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uio.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uio.pyi new file mode 100644 index 000000000..514a4f945 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uio.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to io +from io import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ujson.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ujson.pyi new file mode 100644 index 000000000..0de669254 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ujson.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to json +from json import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/umachine.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/umachine.pyi new file mode 100644 index 000000000..e1fdb35a4 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/umachine.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to machine +from machine import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uos.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uos.pyi new file mode 100644 index 000000000..8c99e764b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uos.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to os +from os import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uplatform.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uplatform.pyi new file mode 100644 index 000000000..22ad247bf --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uplatform.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to platform +from platform import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/urandom.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/urandom.pyi new file mode 100644 index 000000000..b912f0793 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/urandom.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to random +from random import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ure.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ure.pyi new file mode 100644 index 000000000..dbe8b6a52 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ure.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to re +from re import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/urequests.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/urequests.pyi new file mode 100644 index 000000000..d53bcfbeb --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/urequests.pyi @@ -0,0 +1 @@ +def __getattr__(attr): ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uselect.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uselect.pyi new file mode 100644 index 000000000..a543041c4 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uselect.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to select +from select import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/usocket.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/usocket.pyi new file mode 100644 index 000000000..140590c29 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/usocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to socket +from socket import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ussl.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ussl.pyi new file mode 100644 index 000000000..3115761c4 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ussl.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to ssl +from ssl import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/ustruct.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/ustruct.pyi new file mode 100644 index 000000000..0f7fb657a --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/ustruct.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to struct +from struct import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/usys.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/usys.pyi new file mode 100644 index 000000000..298d7a8ac --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/usys.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to sys +from sys import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/utime.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/utime.pyi new file mode 100644 index 000000000..1f972a5b6 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/utime.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to time +from time import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uwebsocket.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uwebsocket.pyi new file mode 100644 index 000000000..afa801ba2 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uwebsocket.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to websocket +from websocket import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/uzlib.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/uzlib.pyi new file mode 100644 index 000000000..5fad9a23c --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/uzlib.pyi @@ -0,0 +1,2 @@ +# This umodule is a MicroPython reference to zlib +from zlib import * diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/vfs.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/vfs.pyi new file mode 100644 index 000000000..97e4941f1 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/vfs.pyi @@ -0,0 +1,240 @@ +""" +Virtual filesystem control. + +MicroPython module: https://docs.micropython.org/en/v1.26.0/library/vfs.html + +The ``vfs`` module contains functions for creating filesystem objects and +mounting/unmounting them in the Virtual Filesystem. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +--- +Module: 'vfs' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete +from _mpy_shed import _BlockDeviceProtocol +from abc import ABC, abstractmethod +from typing import List, overload +from typing_extensions import Awaitable, TypeAlias, TypeVar + +def umount(mount_point: Incomplete) -> Incomplete: + """ + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + """ + ... + +@overload +def mount(fsobj, mount_point: str, *, readonly: bool = False) -> None: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +@overload +def mount() -> List[tuple[Incomplete, str]]: + """ + :noindex: + + With no arguments to :func:`mount`, return a list of tuples representing + all active mountpoints. + + The returned list has the form *[(fsobj, mount_point), ...]*. + """ + ... + +class VfsLfs2: + """ + Create a filesystem object that uses the `littlefs v2 filesystem format`_. + Storage of the littlefs filesystem is provided by *block_dev*, which must + support the :ref:`extended interface `. + Objects created by this constructor can be mounted using :func:`mount`. + + The *mtime* argument enables modification timestamps for files, stored using + littlefs attributes. This option can be disabled or enabled differently each + mount time and timestamps will only be added or updated if *mtime* is enabled, + otherwise the timestamps will remain untouched. Littlefs v2 filesystems without + timestamps will work without reformatting and timestamps will be added + transparently to existing files once they are opened for writing. When *mtime* + is enabled `os.stat` on files without timestamps will return 0 for the timestamp. + + See :ref:`filesystem` for more information. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32) -> None: + """ + Build a Lfs2 filesystem on *block_dev*. + + ``Note:`` There are reports of littlefs v2 failing in certain situations, + for details see `littlefs issue 295`_. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev, readsize=32, progsize=32, lookahead=32, mtime=True) -> None: ... + +class VfsFat: + """ + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + """ + def rename(self, *args, **kwargs) -> Incomplete: ... + @staticmethod + def mkfs(block_dev: AbstractBlockDev) -> None: + """ + Build a FAT filesystem on *block_dev*. + """ + ... + def mount(self, *args, **kwargs) -> Incomplete: ... + def statvfs(self, *args, **kwargs) -> Incomplete: ... + def rmdir(self, *args, **kwargs) -> Incomplete: ... + def stat(self, *args, **kwargs) -> Incomplete: ... + def umount(self, *args, **kwargs) -> Incomplete: ... + def remove(self, *args, **kwargs) -> Incomplete: ... + def mkdir(self, *args, **kwargs) -> Incomplete: ... + def open(self, *args, **kwargs) -> Incomplete: ... + def ilistdir(self, *args, **kwargs) -> Incomplete: ... + def chdir(self, *args, **kwargs) -> Incomplete: ... + def getcwd(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, block_dev: AbstractBlockDev) -> None: ... + +class AbstractBlockDev: + # + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray) -> bool: ... + @abstractmethod + @overload + def readblocks(self, block_num: int, buf: bytearray, offset: int) -> bool: + """ + The first form reads aligned, multiples of blocks. + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows reading at arbitrary locations within a block, + and arbitrary lengths. + Starting at block index *block_num*, and byte offset within that block + of *offset*, read bytes from the device into *buf* (an array of bytes). + The number of bytes to read is given by the length of *buf*. + """ + ... + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + + @abstractmethod + @overload + def writeblocks(self, block_num: int, buf: bytes | bytearray, offset: int, /) -> None: + """ + The first form writes aligned, multiples of blocks, and requires that the + blocks that are written to be first erased (if necessary) by this method. + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + The second form allows writing at arbitrary locations within a block, + and arbitrary lengths. Only the bytes being written should be changed, + and the caller of this method must ensure that the relevant blocks are + erased via a prior ``ioctl`` call. + Starting at block index *block_num*, and byte offset within that block + of *offset*, write bytes from *buf* (an array of bytes) to the device. + The number of bytes to write is given by the length of *buf*. + + Note that implementations must never implicitly erase blocks if the offset + argument is specified, even if it is zero. + """ + ... + + @abstractmethod + @overload + def ioctl(self, op: int, arg) -> int | None: ... + # + @abstractmethod + @overload + def ioctl(self, op: int) -> int | None: + """ + Control the block device and query its parameters. The operation to + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 5 -- get the number of bytes in a block, should return an integer, + or ``None`` in which case the default value of 512 is used + (*arg* is unused) + - 6 -- erase a block, *arg* is the block number to erase + + As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs + ``ioctl(6, ...)`` must also be intercepted. The need for others is + hardware dependent. + + Prior to any call to ``writeblocks(block, ...)`` littlefs issues + ``ioctl(6, block)``. This enables a device driver to erase the block + prior to a write if the hardware requires it. Alternatively a driver + might intercept ``ioctl(6, block)`` and return 0 (success). In this case + the driver assumes responsibility for detecting the need for erasure. + + Unless otherwise stated ``ioctl(op, arg)`` can return ``None``. + Consequently an implementation can ignore unused values of ``op``. Where + ``op`` is intercepted, the return value for operations 4 and 5 are as + detailed above. Other operations should return 0 on success and non-zero + for failure, with the value returned being an ``OSError`` errno code. + """ + ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/webrepl.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/webrepl.pyi new file mode 100644 index 000000000..92c4ed832 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/webrepl.pyi @@ -0,0 +1,16 @@ +from _typeshed import Incomplete +from micropython import const as const + +listen_s: Incomplete +client_s: Incomplete +DEBUG: int +_DEFAULT_STATIC_HOST: str +static_host = _DEFAULT_STATIC_HOST + +def server_handshake(cl): ... +def send_html(cl) -> None: ... +def setup_conn(port, accept_handler): ... +def accept_conn(listen_sock): ... +def stop() -> None: ... +def start(port: int = 8266, password=None, accept_handler=...) -> None: ... +def start_foreground(port: int = 8266, password=None) -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/webrepl_setup.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/webrepl_setup.pyi new file mode 100644 index 000000000..4fb5ba785 --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/webrepl_setup.pyi @@ -0,0 +1,10 @@ +RC: str +CONFIG: str + +def input_choice(prompt, choices): ... +def getpass(prompt): ... +def input_pass(): ... +def exists(fname): ... +def get_daemon_status(): ... +def change_daemon(action) -> None: ... +def main() -> None: ... diff --git a/publish/micropython-v1_26_1-mimxrt-stubs/websocket.pyi b/publish/micropython-v1_26_1-mimxrt-stubs/websocket.pyi new file mode 100644 index 000000000..62bf8e79b --- /dev/null +++ b/publish/micropython-v1_26_1-mimxrt-stubs/websocket.pyi @@ -0,0 +1,17 @@ +""" +Module: 'websocket' on micropython-v1.26.1-mimxrt-SEEED_ARCH_MIX +""" + +# MCU: {'variant': '', 'build': '', 'arch': 'armv7emdp', 'port': 'mimxrt', 'board': 'SEEED_ARCH_MIX', 'board_id': 'SEEED_ARCH_MIX', 'mpy': 'v6.3', 'ver': '1.26.1', 'family': 'micropython', 'cpu': 'MIMXRT1052DVL5B', 'version': '1.26.1'} +# Stubber: v1.26.3 +from __future__ import annotations +from _typeshed import Incomplete + +class websocket: + def readline(self, *args, **kwargs) -> Incomplete: ... + def ioctl(self, *args, **kwargs) -> Incomplete: ... + def write(self, *args, **kwargs) -> Incomplete: ... + def close(self, *args, **kwargs) -> Incomplete: ... + def readinto(self, *args, **kwargs) -> Incomplete: ... + def read(self, *args, **kwargs) -> Incomplete: ... + def __init__(self, *argv, **kwargs) -> None: ... From 1ea8fd3f2c1ca31aeb41810c87b7d91224b384dc Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Wed, 26 Nov 2025 12:06:18 +0100 Subject: [PATCH 5/5] data: update publication status Signed-off-by: Jos Verlinde --- data/all_packages.db | Bin 184320 -> 184320 bytes data/stub-packages.json | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/data/all_packages.db b/data/all_packages.db index 14c0fbfb2a6f09bcc523d9d272b64def20ec826f..420b2ceb6d821cc226d73519fce780d7bb5a420a 100644 GIT binary patch delta 827 zcmbV~&1(}u7>5&~m=bMH9zxdKJV;0~A3HNUhk_w4HIxWOEdeR(&KC`38`(sy^F7P?o1i&R=eA|cT(rBEKg+=PRWQG$BjSqf9EFjnBbU!0?2Jag(3tqjZAzfB^6T2 zhg3_f2$tH{HjVKi7LI0&`%p6>9U1@CGEO0}4f>0IwzJyG^5|(wZxu3&$ttwtRVbaY z3g_d_D*d0?PlxRbObk)RI7%`kg)a$(&`5v~QDoRJ(u0i3a5q`wFP4D